/*
 * Ingenic IMP OSD solution.
 * The region concept is equals to channel which is a
 * draw unit infomation node.
 *
 * Copyright (C) 2015 Ingenic Semiconductor Co.,Ltd
 * Author: Justin <pengtao.kang@ingenic.com>
 */

#include <stdio.h>
#include <string.h>
#include <semaphore.h>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <imp/imp_log.h>
#include <imp/imp_osd.h>
#include <imp/isp_osd.h>
#include <constraints.h>
#include <imp/imp_utils.h>

#include <system/system.h>
#include <system/group.h>
#include <system/device.h>
#include <system/vbm.h>
#include <fifo.h>
#include "jz_ipu_hal.h"
#include "osd_mem.h"
#ifdef DMALLOC
#include <imp/dmalloc.h>
#endif
#define IS_SOC_SERIES(ID) ((SOC_##ID##_START <= get_cpu_id()) && (get_cpu_id() <= SOC_##ID##_END))
#define OSD_IPU_BUF_SIZE  (1)
#define OSD_ATTR_FIFO_SIZE  (25)

/*osd 寻址的偏移，和frame内存申请的偏移保持一致,T41 w(32-1),h(16-1)对齐*/
#define OSDWALIGN (15)
#define OSDHALIGN (15)

typedef enum IMPOSDNodeStatus {
	IMP_OSD_RGN_FREE		= 0,
	IMP_OSD_RGN_BUSY		= 1,
} IMPOSDNodeStatus;

typedef struct IMPOsdRgnNode IMPOsdRgnNode;
struct IMPOsdRgnNode {
	int					rAttrIndex;
	IMPOSDRgnAttr		rAttr;
	IMPOSDNodeStatus	status;
	int					refcnt;
	IMPOsdRgnNode		*prev;
	IMPOsdRgnNode		*next;
	void *attrfifo;
};

typedef struct {
	IMPOsdRgnNode	*head;
	IMPOsdRgnNode	*tail;
} IMPOsdRgnList;


typedef struct IMPOSDHalfStatus IMPOSDHalfStatus;
struct IMPOSDHalfStatus {
    int                 lastDrawLine;
};

typedef struct IMPOsdGrpRgnNode IMPOsdGrpRgnNode;
struct IMPOsdGrpRgnNode {
	int					grAttrIndex;
	IMPOSDNodeStatus	status;
	IMPOSDGrpRgnAttr	grAttr;
    IMPOSDHalfStatus    grHalfStatus[5];
	IMPOsdGrpRgnNode	*prev;
	IMPOsdGrpRgnNode	*next;
};

typedef struct {
	IMPOsdGrpRgnNode	*head;
	IMPOsdGrpRgnNode	*tail;
} IMPOsdGrpRgnList;

typedef struct {
	int						index;
	IMPOsdGrpRgnNode		grnode[NR_MAX_OSD_REGION];
	IMPOsdGrpRgnList		busygrlist;
	int						is_work;
    int                     is_left_prio_modified;
} IMPOsdGroup;

typedef struct {
	IMPOSDRgnAttr attr;
	IMPOSDRgnTimestamp ts;
} IMPOSDRgnAttrFifoData;

typedef struct {
	IMPOsdGroup				group[NR_MAX_OSD_GROUPS];
	IMPOsdRgnNode			rnode[NR_MAX_OSD_REGION];
	sem_t					registerlock;
	sem_t					semRgnList;
	IMPOsdRgnList			freerlist;
	IMPOsdRgnList			busyrlist;
	Device					*device;
    mem_alloc_info_t*       osd_mem;
	/*打开OSD标志，当该位置为0时，表示只绘制ISPOSD，当该位置为1，表示既可以绘制ISPOSD又可以绘制区域的OSD(ipu/软件绘制)，默认该位为1*/
	volatile uint32_t       bISPopenosd;
	pthread_mutex_t         ISPOsdmutex;
} IMPOsd;

#define TAG "OSD"

static IMPOsd *gosd = NULL;
static int pool_size = OSD_IPU_BUF_SIZE;
IMPAlloc alloc_ipu;

#define IPU_OSD_FLAGS(a) (1 << (a))
static int Convert1555To8888(void *pData, void *picData, int newrectsize);

static IMPOsd *alloc_osd(void)
{
	IMPOsd *osd = NULL;

	memset(&alloc_ipu, 0, sizeof(alloc_ipu));
	if (IMP_Alloc(&alloc_ipu, pool_size, "osdDev") < 0) {
		IMP_LOG_ERR(TAG, "IMP_Alloc(%d) failed\n", pool_size);
		return NULL;
	}
	//IMP_LOG_DBG(TAG, "%s(%d):alloc_ipu.info.vaddr=%x, alloc_ipu.info.vaddr=%x, alloc_ipu.info.length=%d\n", __func__, __LINE__, alloc_ipu.info.vaddr, alloc_ipu.info.paddr, alloc_ipu.info.length);

	Device *dev = alloc_device(TAG, sizeof(IMPOsd));
	if (dev == NULL) {
		IMP_LOG_ERR(TAG, "alloc_device() error\n");
		goto err_alloc_device_osd;
	}

	dev->nr_groups = NR_MAX_OSD_GROUPS;
	dev->dev_id = DEV_ID_OSD;

	osd = device_pri(dev);
	osd->device = dev;
    osd->osd_mem = OSD_mem_create((void*)alloc_ipu.info.vaddr, pool_size);
    if (osd->osd_mem == NULL) {
        IMP_LOG_ERR(TAG, "OSD_mem_create() error\n");
        goto err_alloc_mem_create;
    }
	return osd;
err_alloc_mem_create:
err_alloc_device_osd:
	IMP_Free(&alloc_ipu, (void *)alloc_ipu.info.vaddr);
	return NULL;
}

static void free_osd(IMPOsd *osd)
{
	OSD_mem_destroy(osd->osd_mem);
	Device *dev = osd->device;
	free_device(dev);
	IMP_Free(&alloc_ipu, (void *)alloc_ipu.info.vaddr);
	memset(&alloc_ipu, 0, sizeof(alloc_ipu));
}

static IMPOsd *getOsd()
{
	return gosd;
}

static void setOsd(IMPOsd *osd)
{
	gosd = osd;
}

int OSDInit(void)
{
	int i = 0;
	IMPOsd *osd = alloc_osd();

	if (osd == NULL) {
		IMP_LOG_ERR(TAG, "alloc_osd failed!\n");
		goto err_alloc_osd;
	}

	if (sem_init(&osd->registerlock, 0, 1) < 0) {
		IMP_LOG_ERR(TAG, "sem_init osd->registerlock failed!\n");
		goto err_sem_init_registerlock;
	}

	if (sem_init(&osd->semRgnList, 0, 1) < 0) {
		IMP_LOG_ERR(TAG, "sem_init osd->semRgnList failed!\n");
		goto err_sem_init_semRgnList;
	}

	for (i = 0; i < NR_MAX_OSD_REGION; i++) {
		osd->rnode[i].rAttrIndex = i;
		if (i == 0) {
			osd->freerlist.head = osd->freerlist.tail = &osd->rnode[0];
			osd->freerlist.tail->prev = NULL;
			osd->freerlist.tail->next = NULL;
		} else {
			osd->freerlist.tail->next = &osd->rnode[i];
			osd->freerlist.tail->next->prev = osd->freerlist.tail;
			osd->freerlist.tail = osd->freerlist.tail->next;
			osd->freerlist.tail->next = NULL;
		}
	}

	setOsd(osd);
	/*ISPOSD的初始化*/
	if (IMP_OSD_Init_ISP() < 0) {
		IMP_LOG_ERR(TAG, "IMP_OSD_Init_ISP failed!\n");
		goto err_alloc_osd;
	}

	return 0;

err_sem_init_semRgnList:
	sem_destroy(&osd->registerlock);
err_sem_init_registerlock:
	free_osd(osd);
	osd = NULL;
err_alloc_osd:
	return IMP_ERR_OSD_RESOURCE_REQUEST;
}

int OSDExit(void )
{
	IMPOsd *osd = getOsd();
	sem_destroy(&osd->semRgnList);
	sem_destroy(&osd->registerlock);
	free_osd(osd);
	setOsd(NULL);
	IMP_OSD_Exit_ISP();
	return 0;
}

static inline int osd_clip3(int x, int min, int max)
{
	if (x < min) x = min;
	if (x > max) x = max;

	return x;
}

static inline int osd_max(int x, int y)
{
	return x > y ? x : y;
}

static inline int osd_min(int x, int y)
{
	return x < y ? x : y;
}

static inline uint32_t osd_rgnsize(IMPOSDRgnAttr *prAttr)
{
	int bytesperpixel = 1;
	if (prAttr->type == OSD_REG_BITMAP) {
		bytesperpixel = 1;
	} else if ((prAttr->type == OSD_REG_PIC)||(prAttr->type == OSD_REG_PIC_RMEM)) {
		if(IS_SOC_SERIES(T10)) {
			bytesperpixel = 4;
		} else {
			if(prAttr->fmt == PIX_FMT_BGR555LE || prAttr->fmt == PIX_FMT_RGB555LE) {
				bytesperpixel = 2;
			} else if ((prAttr->fmt == PIX_FMT_NV12) || (prAttr->fmt == PIX_FMT_NV21)) {
				return (abs(prAttr->rect.p1.x - prAttr->rect.p0.x) + 1) * (abs(prAttr->rect.p1.y - prAttr->rect.p0.y) + 1) * 3 / 2;
			} else {
				bytesperpixel = 4;
			}
		}
	}
	return (abs(prAttr->rect.p1.x - prAttr->rect.p0.x) + 1) * (abs(prAttr->rect.p1.y - prAttr->rect.p0.y) + 1) * bytesperpixel;
}

/**
 * y = (unsigned char)(( 66 * r + 129 * g +  25 * b + 128) >> 8)
 * u = (unsigned char)((-38 * r -  74 * g + 112 * b + 128) >> 8) + 128
 * v = (unsigned char)((112 * r -  94 * g -  18 * b + 128) >> 8) + 128
 */
static inline uint32_t bgra_to_nv12(uint32_t bgra)
{
	uint8_t y, u, v, r = (bgra >> 16) & 0xff, g = (bgra >> 8) & 0xff, b = bgra & 0xff, a = (bgra >> 24) & 0xff;
	y = osd_clip3((( 66 * r + 129 * g +  25 * b + 128) >> 8) + 0,   0, 255);
	u = osd_clip3(((-38 * r -  74 * g + 112 * b + 128) >> 8) + 128, 0, 255);
	v = osd_clip3(((112 * r -  94 * g -  18 * b + 128) >> 8) + 128, 0, 255);
	return (a << 24) | (y << 16) | (u << 8) | (v << 0);
}

static void bgra_correct_ipu_alhpa(uint8_t *data, uint32_t size, uint32_t globalAlpha)
{
	int i = 0;
	if (size < 4) {
		return;
	}
	for (i = 3; i < size; i += 4) {
		data[i] = (data[i] * (globalAlpha + 1)) / 0x100;
	}
}

static inline void osd_draw_short_line(uint8_t *pAddr, int xmin, int xmax, int ymin, int ymax,
		uint8_t cy, uint8_t cu, uint8_t cv, int w, int h)
{
	int i = 0, j = 0;
	for (j = ymin; j <= ymax; j++) {
		for (i = xmin; i <= xmax; i++) {
            pAddr[j * w + i] = cy;
            pAddr[(w * h + (j / 2) * w + i) & (~(0x1))] = cu;
            pAddr[((w * h +(j / 2) * w + i) & (~(0x1)))+1] = cv;
		}
	}
}

static void osd_draw_line(IMPFrameInfo *frame, IMPOSDRgnAttr *prAttr, IMPOSDGrpRgnAttr *pgrAttr, IMPOSDHalfStatus *grHalfStatus, int is_left)
{
    if ((prAttr->rect.p0.x == prAttr->rect.p1.x) && (prAttr->rect.p0.y == prAttr->rect.p1.y)) return;

	int x0 = prAttr->rect.p0.x * pgrAttr->scalex, y0 = prAttr->rect.p0.y * pgrAttr->scaley;
	int x1 = prAttr->rect.p1.x * pgrAttr->scalex, y1 = prAttr->rect.p1.y * pgrAttr->scaley;
	int realFrmWidth = (frame->width + OSDWALIGN) & ~OSDWALIGN, realFrmHeight = (frame->height + OSDHALIGN) & ~OSDHALIGN;
    int yAvail = 0;
    IMPFrameInfoPriv* framePriv = (IMPFrameInfoPriv *)(frame->priv);

	if ((x0 > (frame->width - 1)) || (x1 > (frame->width - 1)) || (y0 > (frame->height - 1)) || (y1 > (frame->height - 1))) {
		//IMP_LOG_WARN(TAG, "%s:srange((%d,%d),(%d,%d))*scale=(%f,%f)=drange((%d,%d),(%d,%d)) overflow the (w,h)=(%d,%d)\n",
		//		__func__, prAttr->rect.p0.x, prAttr->rect.p0.y, prAttr->rect.p1.x, prAttr->rect.p1.y,
		//		pgrAttr->scalex, pgrAttr->scaley, x0, y0, x1, y1, frame->width, frame->height);
        if(x0 > (frame->width - 1)) {
            x0 = frame->width - 1;
        }
        if(x1 > (frame->width - 1)) {
            x1 = frame->width - 1;
        }
        if(y0 > (frame->height - 1)) {
            y0 = frame->height - 1;
        }
        if(y1 > (frame->height - 1)) {
            y1 = frame->height - 1;
        }
	}

	int extend = prAttr->data.lineRectData.linewidth / 2;
	uint8_t *pAddr = (uint8_t *)frame->virAddr;
	x0 = osd_clip3(x0 + pgrAttr->offPos.x, 0, frame->width - 1);
	y0 = osd_clip3(y0 + pgrAttr->offPos.y, 0, frame->height - 1);
	x1 = osd_clip3(x1 + pgrAttr->offPos.x, 0, frame->width - 1);
	y1 = osd_clip3(y1 + pgrAttr->offPos.y, 0, frame->height - 1);

    int is_vline = (abs(x1 - x0) < prAttr->data.lineRectData.linewidth * 2) ? 1 : 0;

	if ((prAttr->fmt == PIX_FMT_MONOWHITE)/* && frame->pixfmt == PIX_FMT_NV12*/) {
        uint32_t nv12 = bgra_to_nv12(prAttr->data.lineRectData.color);
        uint8_t cy = (nv12 >> 16) & 0xff, cu = (nv12 >> 8) & 0xff, cv = (nv12 >> 0) & 0xff;

		if (is_vline) {
			int minx = 0, maxx = 0, miny = 0, maxy = 0;
			minx = (x0 + x1) / 2 - extend;
			minx = osd_clip3(minx, 0, frame->width - 1);
			maxx = minx + prAttr->data.lineRectData.linewidth - 1;
			maxx = osd_clip3(maxx, 0, frame->width - 1);
			miny = osd_min(y1, y0);
			miny = miny - extend;
			miny = osd_clip3(miny, 0, frame->height - 1);
			maxy = osd_max(y1, y0);
			maxy = maxy - extend;
			maxy = osd_clip3(maxy + prAttr->data.lineRectData.linewidth - 1, 0, frame->height - 1);
			osd_draw_short_line(pAddr, minx, maxx, miny, maxy,
					cy, cu, cv, realFrmWidth, realFrmHeight);
		} else {
			float k = 1.0 * (y1 - y0) / (x1 - x0);
			int direct = 0;
			int x = 0, y = 0;
			int minx = 0, maxx = 0, miny = 0, maxy = 0;
			if (abs(k) < 1.0) {
				direct = x1 > x0 ? 1 : -1;
				for (x = x0; x != x1; x += (direct * 1)) {
					y = k * (x - x0) + y0;
					minx = osd_clip3(x - extend, 0, frame->width - 1);
					maxx = osd_clip3(minx + prAttr->data.lineRectData.linewidth - 1, 0, frame->width - 1);
					miny = osd_clip3(y - extend, 0, frame->height - 1);
					maxy = osd_clip3(miny + prAttr->data.lineRectData.linewidth - 1, 0,  frame->height - 1);
					osd_draw_short_line(pAddr, minx, maxx, miny, maxy,
							cy, cu, cv, realFrmWidth, realFrmHeight);
				}
			} else {
				direct = y1 > y0 ? 1 : -1;
				for (y = y0; y != y1; y += (direct * 1)) {
					x =  (y - y0) / k + x0;
					minx = osd_clip3(x - extend, 0, frame->width - 1);
					maxx = osd_clip3(minx + prAttr->data.lineRectData.linewidth - 1, 0, frame->width - 1);
					miny = osd_clip3(y - extend, 0, frame->height - 1);
					maxy = osd_clip3(miny + prAttr->data.lineRectData.linewidth - 1, 0,  frame->height - 1);
					osd_draw_short_line(pAddr, minx, maxx, miny, maxy,
							cy, cu, cv, realFrmWidth, realFrmHeight);
				}
			}
		}
	}
}

static void osd_draw_rect(IMPFrameInfo *frame, IMPOSDRgnAttr *prAttr, IMPOSDGrpRgnAttr *pgrAttr, IMPOSDHalfStatus *grHalfStatus, int is_left)
{
	IMPOSDRgnAttr rAttr;
    IMPFrameInfoPriv* framePriv = (IMPFrameInfoPriv *)(frame->priv);

    if ((prAttr->rect.p0.x == prAttr->rect.p1.x) && (prAttr->rect.p0.y == prAttr->rect.p1.y)) return;

	memcpy(&rAttr, prAttr, sizeof(IMPOSDRgnAttr));
	rAttr.rect.p0.x = prAttr->rect.p0.x;
	rAttr.rect.p0.y = prAttr->rect.p0.y;
	rAttr.rect.p1.x = prAttr->rect.p1.x;
	rAttr.rect.p1.y = prAttr->rect.p0.y;
#ifdef DEBUG_FAST_FRAME
    IMP_LOG_INFO(TAG, "%s(%d):is_left=%d, frame->type=%d, x0=%d, x1=%d, y0=%d, y1=%d\n", __func__, __LINE__, is_left,
            ((IMPFrameInfoPriv *)(frame->priv))->frame_type, rAttr.rect.p0.x, rAttr.rect.p1.x, rAttr.rect.p0.y, rAttr.rect.p1.y);
#endif
	osd_draw_line(frame, &rAttr, pgrAttr, &(grHalfStatus[1]), is_left);

	rAttr.rect.p0.x = prAttr->rect.p0.x;
	rAttr.rect.p0.y = prAttr->rect.p0.y;
	rAttr.rect.p1.x = prAttr->rect.p0.x;
	rAttr.rect.p1.y = prAttr->rect.p1.y;
#ifdef DEBUG_FAST_FRAME
    IMP_LOG_INFO(TAG, "%s(%d):is_left=%d, frame->type=%d, x0=%d, x1=%d, y0=%d, y1=%d\n", __func__, __LINE__, is_left,
            ((IMPFrameInfoPriv *)(frame->priv))->frame_type, rAttr.rect.p0.x, rAttr.rect.p1.x, rAttr.rect.p0.y, rAttr.rect.p1.y);
#endif
	osd_draw_line(frame, &rAttr, pgrAttr, &(grHalfStatus[2]), is_left);

	rAttr.rect.p0.x = prAttr->rect.p0.x;
	rAttr.rect.p0.y = prAttr->rect.p1.y;
	rAttr.rect.p1.x = prAttr->rect.p1.x;
	rAttr.rect.p1.y = prAttr->rect.p1.y;
#ifdef DEBUG_FAST_FRAME
    IMP_LOG_INFO(TAG, "%s(%d):is_left=%d, frame->type=%d, x0=%d, x1=%d, y0=%d, y1=%d\n", __func__, __LINE__, is_left,
            ((IMPFrameInfoPriv *)(frame->priv))->frame_type, rAttr.rect.p0.x, rAttr.rect.p1.x, rAttr.rect.p0.y, rAttr.rect.p1.y);
#endif
	osd_draw_line(frame, &rAttr, pgrAttr, &(grHalfStatus[3]), is_left);

	rAttr.rect.p0.x = prAttr->rect.p1.x;
	rAttr.rect.p0.y = prAttr->rect.p0.y;
	rAttr.rect.p1.x = prAttr->rect.p1.x;
	rAttr.rect.p1.y = prAttr->rect.p1.y;
#ifdef DEBUG_FAST_FRAME
    IMP_LOG_INFO(TAG, "%s(%d):is_left=%d, frame->type=%d, x0=%d, x1=%d, y0=%d, y1=%d\n", __func__, __LINE__, is_left,
            ((IMPFrameInfoPriv *)(frame->priv))->frame_type, rAttr.rect.p0.x, rAttr.rect.p1.x, rAttr.rect.p0.y, rAttr.rect.p1.y);
#endif
	osd_draw_line(frame, &rAttr, pgrAttr, &(grHalfStatus[4]), is_left);
}

/* now bitmap only means datetime, so the black color in enough and needn't scale */
static void osd_draw_bitmap(IMPFrameInfo *frame, IMPOSDRgnAttr *prAttr, IMPOSDGrpRgnAttr *pgrAttr, IMPOSDHalfStatus *grHalfStatus, int is_left)
{
	int i = 0, j = 0;
	int minx = 0, maxx = 0, miny = 0, maxy = 0, width = 0;
	uint8_t *pAddr = (uint8_t *)frame->virAddr;
	int realFrmWidth = (frame->width + OSDWALIGN) & ~OSDWALIGN, realFrmHeight = (frame->height + OSDHALIGN) & ~OSDHALIGN;
    int yAvail = 0;
    IMPFrameInfoPriv* framePriv = (IMPFrameInfoPriv *)(frame->priv);

	if ((prAttr->rect.p0.x > (frame->width - 1)) || (prAttr->rect.p1.x > (frame->width - 1)) || (prAttr->rect.p0.y > (frame->height - 1)) || (prAttr->rect.p1.y > (frame->height - 1))) {
		//IMP_LOG_WARN(TAG, "%s:srange((%d,%d),(%d,%d)) overflow the (w,h)=(%d,%d)\n",
		//		__func__, prAttr->rect.p0.x, prAttr->rect.p0.y, prAttr->rect.p1.x, prAttr->rect.p1.y, frame->width, frame->height);
        if(prAttr->rect.p0.x > (frame->width - 1)) {
            prAttr->rect.p0.x = frame->width - 1;
        }
        if(prAttr->rect.p1.x > (frame->width - 1)) {
            prAttr->rect.p1.x = frame->width - 1;
        }
        if(prAttr->rect.p0.y > (frame->height - 1)) {
            prAttr->rect.p0.y = frame->height - 1;
        }
        if(prAttr->rect.p1.y > (frame->height - 1)) {
            prAttr->rect.p1.y = frame->height - 1;
        }
	}
	minx = osd_clip3(osd_min(prAttr->rect.p0.x, prAttr->rect.p1.x) + pgrAttr->offPos.x, 0, frame->width - 1);
	maxx = osd_clip3(osd_max(prAttr->rect.p0.x, prAttr->rect.p1.x) + pgrAttr->offPos.x, 0, frame->width - 1);
	miny = osd_clip3(osd_min(prAttr->rect.p0.y, prAttr->rect.p1.y) + pgrAttr->offPos.y, 0, frame->height - 1);
	maxy = osd_clip3(osd_max(prAttr->rect.p0.y, prAttr->rect.p1.y) + pgrAttr->offPos.y, 0, frame->height - 1);


retry_check_point:
	width = maxx - minx + 1;
	for (j = miny; j <= maxy; j++) {
		for (i = minx; i <= maxx; i++) {
			if (((uint8_t *)prAttr->data.bitmapData)[(j-miny)*width+(i-minx)] != 0) {
				pAddr[j*realFrmWidth+i] = ((uint8_t *)prAttr->data.bitmapData)[(j-miny)*width+(i-minx)];
				pAddr[realFrmWidth*realFrmHeight+(j/2)*realFrmWidth+i] = 128;
			}
		}
	}
}

static unsigned int application_to_hal_fmt(IMPPixelFormat app_fmt)
{
	unsigned int hal_fmt = HAL_PIXEL_FORMAT_BGRA_8888;
	switch (app_fmt) {
		case PIX_FMT_BGRA:
			hal_fmt = HAL_PIXEL_FORMAT_BGRA_8888;
			break;
		case PIX_FMT_RGBA:
			hal_fmt = HAL_PIXEL_FORMAT_RGBA_8888;
			break;
		case PIX_FMT_ABGR:
			hal_fmt = HAL_PIXEL_FORMAT_ABGR_8888;
			break;
		case PIX_FMT_ARGB:
			hal_fmt = HAL_PIXEL_FORMAT_ARGB_8888;
			break;
		case PIX_FMT_BGR555LE:
			hal_fmt = HAL_PIXEL_FORMAT_BGRA_5551;
			break;
		case PIX_FMT_RGB555LE:
			hal_fmt = HAL_PIXEL_FORMAT_RGBA_5551;
			break;
		case PIX_FMT_NV12:
			hal_fmt = HAL_PIXEL_FORMAT_NV12;
			break;
		case PIX_FMT_NV21:
			hal_fmt = HAL_PIXEL_FORMAT_NV21;
			break;
		case PIX_FMT_YUV420P:
			hal_fmt = HAL_PIXEL_FORMAT_YCbCr_420_P;
			break;
		default:
			hal_fmt = HAL_PIXEL_FORMAT_BGRA_8888;
			break;
	}
	return hal_fmt;
}

void* osd_mem_vir_to_phy(void* vaddr)
{
    void* paddr = (vaddr - alloc_ipu.info.vaddr + alloc_ipu.info.paddr);
#if 0
    printf("vaddr = %p, paddr = %p, rmem vaddr = %p, rmem paddr = %p\n",
            vaddr, paddr, alloc_ipu.info.vaddr, alloc_ipu.info.paddr);
#endif
    return paddr;
}


static int osd_draw_cover_pic(IMPFrameInfo *frame, IMPOSDRgnAttr *prAttr, IMPOSDGrpRgnAttr *pgrAttr, struct ipu_osd_param *ipu_osdp, int layer)
{
	int minx = 0, maxx = 0, miny = 0, maxy = 0;
	int realFrmWidth = (frame->width + OSDWALIGN) & ~OSDWALIGN, realFrmHeight = (frame->height + OSDHALIGN) & ~OSDHALIGN;

    if ((osd_min(prAttr->rect.p0.x, prAttr->rect.p1.x) > (frame->width - 1)) || (osd_min(prAttr->rect.p0.y, prAttr->rect.p1.y) > (frame->height - 1))) {
        IMP_LOG_ERR(TAG, "%s(%d):invalid param  p0(%d,%d)-p1(%d,%d)), (w,h)=(%d,%d),You should keep the smallest coordinates within the picture range!!!\n", __func__, __LINE__, prAttr->rect.p0.x, prAttr->rect.p0.y, prAttr->rect.p1.x, prAttr->rect.p1.y, frame->width, frame->height);
        return IMP_ERR_OSD_NOT_SUPPORT;
    }

    minx = osd_clip3(osd_min(prAttr->rect.p0.x, prAttr->rect.p1.x) + pgrAttr->offPos.x, 0, frame->width - 1);
	maxx = osd_clip3(osd_max(prAttr->rect.p0.x, prAttr->rect.p1.x) + pgrAttr->offPos.x, 0, frame->width - 1);
	miny = osd_clip3(osd_min(prAttr->rect.p0.y, prAttr->rect.p1.y) + pgrAttr->offPos.y, 0, frame->height - 1);
	maxy = osd_clip3(osd_max(prAttr->rect.p0.y, prAttr->rect.p1.y) + pgrAttr->offPos.y, 0, frame->height - 1);

	if ((minx == maxx) || (miny == maxy)) {
		IMP_LOG_ERR(TAG, "%s(%d):invalid param when correct p0(%d,%d)-p1(%d,%d)) to p0(%d,%d)-p1(%d,%d)) when (w,h)=(%d,%d)\n", __func__, __LINE__, prAttr->rect.p0.x, prAttr->rect.p0.y, prAttr->rect.p1.x, prAttr->rect.p1.y, minx, miny, maxx, maxy, frame->width, frame->height);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}

    if (ipu_osdp == NULL) {
		IMP_LOG_ERR(TAG, "%s, ipu_osdp is NULL,ipu can not work!\n", __func__);
		return IMP_ERR_OSD_NULL_PTR;
 	}

	if (prAttr->type == OSD_REG_COVER) {
		ipu_osdp->osd_flags |= IPU_OSD_FLAGS(layer);
		ipu_osdp->bg_w = realFrmWidth;    //16_byte alignment
		ipu_osdp->bg_h = realFrmHeight;
		ipu_osdp->bg_fmt =  HAL_PIXEL_FORMAT_NV12;
		ipu_osdp->bg_buf = frame->phyAddr;
		ipu_osdp->bg_buf_v = frame->virAddr;

		if (pgrAttr->gAlphaEn > 0) {
			ipu_osdp->osd_mask_para = bgra_to_nv12((osd_clip3((((prAttr->data.coverData.color >> 24) & 0xff) * (pgrAttr->fgAlhpa + 1)) / 0x100, 0, 255) << 24)
					| (prAttr->data.coverData.color & 0x00ffffff));
		} else {
			ipu_osdp->osd_mask_para = bgra_to_nv12(prAttr->data.coverData.color);
		}

		if (prAttr->fmt == PIX_FMT_BGRA) {
			ipu_osdp->ch[layer].osd_chx_fmt = HAL_PIXEL_FORMAT_BGRA_8888;
		} else {
			IMP_LOG_ERR(TAG, "%s, COVER cannot support this format!\n", __func__);
			printf("ipu: %s error COVER cannot support this format\n", __func__);
			return IMP_ERR_OSD_NULL_PTR;
		}
		if (IS_SOC_SERIES(T10)) {
//			ipu_osdp->ch[layer].osd_chx_fmt = HAL_PIXEL_FORMAT_BGRA_8888;
			ipu_osdp->ch[layer].osd_chx_alpha = pgrAttr->fgAlhpa;
		} else {
//			ipu_osdp->ch[layer].osd_chx_fmt = application_to_hal_fmt(prAttr->fmt);
			if (pgrAttr->gAlphaEn > 0) {
				ipu_osdp->ch[layer].osd_chx_alpha = pgrAttr->fgAlhpa;
			} else {     //When gAlphaEn is disable use pixel alpha
				ipu_osdp->ch[layer].osd_chx_alpha = (0x1<<8) | pgrAttr->fgAlhpa;
			}
		}
//		ipu_osdp->ch[layer].osd_chx_alpha = pgrAttr->fgAlhpa;
        ipu_osdp->ch[layer].osd_chx_pos_x = osd_min(prAttr->rect.p0.x, prAttr->rect.p1.x);
        ipu_osdp->ch[layer].osd_chx_pos_y = osd_min(prAttr->rect.p0.y, prAttr->rect.p1.y);
		ipu_osdp->ch[layer].osd_chx_src_w = osd_max(prAttr->rect.p0.x, prAttr->rect.p1.x) - osd_min(prAttr->rect.p0.x, prAttr->rect.p1.x)+1;
		ipu_osdp->ch[layer].osd_chx_src_h = osd_max(prAttr->rect.p0.y, prAttr->rect.p1.y) - osd_min(prAttr->rect.p0.y, prAttr->rect.p1.y)+1;
		ipu_osdp->ch[layer].osd_chx_buf = 0;
	} else if ((prAttr->type == OSD_REG_PIC)||(prAttr->type == OSD_REG_PIC_RMEM)) {
		ipu_osdp->osd_flags |= IPU_OSD_FLAGS(layer);
		ipu_osdp->bg_w = realFrmWidth;
		ipu_osdp->bg_h = realFrmHeight;
		ipu_osdp->bg_fmt =  HAL_PIXEL_FORMAT_NV12;
		ipu_osdp->bg_buf = frame->phyAddr;
		ipu_osdp->bg_buf_v = frame->virAddr;

		if (IS_SOC_SERIES(T10)) {
			ipu_osdp->ch[layer].osd_chx_fmt = HAL_PIXEL_FORMAT_BGRA_8888;
			ipu_osdp->ch[layer].osd_chx_alpha = pgrAttr->fgAlhpa;
		} else {
			ipu_osdp->ch[layer].osd_chx_fmt = application_to_hal_fmt(prAttr->fmt);
			if (pgrAttr->gAlphaEn > 0) {
				ipu_osdp->ch[layer].osd_chx_alpha = pgrAttr->fgAlhpa;
			} else {     //When gAlphaEn is disable use pixel alpha
				ipu_osdp->ch[layer].osd_chx_alpha = (0x1<<8) | pgrAttr->fgAlhpa;
			}
		}
//		ipu_osdp->ch[layer].osd_chx_alpha = pgrAttr->fgAlhpa;
        ipu_osdp->ch[layer].osd_chx_pos_x = osd_min(prAttr->rect.p0.x, prAttr->rect.p1.x);
        ipu_osdp->ch[layer].osd_chx_pos_y = osd_min(prAttr->rect.p0.y, prAttr->rect.p1.y);
		ipu_osdp->ch[layer].osd_chx_src_w = osd_max(prAttr->rect.p0.x, prAttr->rect.p1.x) - osd_min(prAttr->rect.p0.x, prAttr->rect.p1.x)+1;
		ipu_osdp->ch[layer].osd_chx_src_h = osd_max(prAttr->rect.p0.y, prAttr->rect.p1.y) - osd_min(prAttr->rect.p0.y, prAttr->rect.p1.y)+1;
		ipu_osdp->ch[layer].osd_chx_buf = (unsigned int)prAttr->data.picData.pData;
        if (prAttr->type == OSD_REG_PIC_RMEM) {
            ipu_osdp->ch[layer].osd_chx_buf_phy = osd_mem_vir_to_phy(ipu_osdp->ch[layer].osd_chx_buf);
        } else {
            ipu_osdp->ch[layer].osd_chx_buf_phy = 0;
        }
	}

	return 0;
}

static int type_is_ipu(IMPOsdRgnType type)
{
	return (type == OSD_REG_PIC || type == OSD_REG_COVER || type == OSD_REG_PIC_RMEM);
}


static int OSD_Draw_Layer_Cover_Pic_RectLine(IMPFrameInfo *frame, IMPOsdGrpRgnNode *grnode, IMPOsd *osd, int is_left)
{
	int count = 0;
	int ret = 0;
	IMPOsdRgnNode *rnode = NULL;
	IMPOsdGrpRgnNode *grnode_tmp = NULL;
	struct ipu_osd_param ipu_osdp;
	memset(&ipu_osdp, 0, sizeof(ipu_osdp));

    IMPFrameInfoPriv* framePriv = (IMPFrameInfoPriv *)(frame->priv);
    int lastLeftLine = 0;
    int maxOsdLayer = 1;
	while (grnode != NULL) {
		grnode_tmp = grnode;
		grnode = grnode->next;
		rnode = &osd->rnode[grnode_tmp->grAttrIndex];
		IMPOSDRgnAttr *rAttr = &rnode->rAttr;
		IMPOSDGrpRgnAttr *grAttr = &grnode_tmp->grAttr;
        IMPOSDHalfStatus *grHalfStatus = &(grnode_tmp->grHalfStatus[0]);
		IMPOSDRgnAttrFifoData *fifodata0 = NULL;
		IMPOSDRgnAttrFifoData *fifodata1 = NULL;
		uint64_t ts0 = 0;
		uint64_t ts1 = 0;
		uint64_t fts = 0;
		if (grnode_tmp->grAttr.show) {
			if (rnode->rAttr.type == OSD_REG_COVER || rnode->rAttr.type == OSD_REG_PIC || rnode->rAttr.type == OSD_REG_PIC_RMEM) {
retry:
				if (rnode->rAttr.type == OSD_REG_PIC_RMEM) {
					maxOsdLayer = 4;
				}
				if (rnode->rAttr.type == OSD_REG_COVER) {
					if (NULL != rnode->attrfifo) {
						int ret = -1;
						ret = fifo_pre_get_ptr(rnode->attrfifo, 0, (uint32_t**)&fifodata0);
						if (0 == ret) {
							ts0 = fifodata0->ts.ts;
						} else {
							fifodata0 = NULL;
						}
						ret = fifo_pre_get_ptr(rnode->attrfifo, 1, (uint32_t**)&fifodata1);
						if (0 == ret) {
							ts1 = fifodata1->ts.ts;
						} else {
							fifodata1 = NULL;
						}
						fts = frame->timeStamp;
						//printf("##### ts0:%lld, ts1:%lld, fts: %lld\n", ts0, ts1, fts);
						if (NULL == fifodata0) {
							//IMP_LOG_ERR(TAG, "err: %s,%d\n", __func__, __LINE__);
							continue;
						} else if (NULL == fifodata1){
							if (fts < ts0) {
								continue;
							} else {
								rAttr = &fifodata0->attr;
							}
						} else {
							if (fts < ts0) {
								continue;
							} else if (fts < ts1) {
								rAttr = &fifodata0->attr;
							} else {
								fifo_get(rnode->attrfifo, NULL);
								goto retry;
							}
						}
					}
				}
				osd_draw_cover_pic(frame, rAttr, grAttr, &ipu_osdp, count);
                {
                    if ((rnode->rAttr.type == OSD_REG_PIC)||(rnode->rAttr.type == OSD_REG_PIC_RMEM)) {
                        char access_name[50];
                        sprintf(access_name, "/tmp/mountdir/osdsnap%d.pic", grnode_tmp->grAttrIndex);
                        if (access(access_name, R_OK | W_OK) == 0) {
                            struct stat stat_buf;
                            int newrectsize = osd_rgnsize(rAttr);
                            stat(access_name, &stat_buf);
                            if (stat_buf.st_size < newrectsize) {
                                int osdsnapfd = open(access_name, O_RDWR | O_APPEND);
                                if (osdsnapfd >= 0) {
                                    write(osdsnapfd, (void *)rAttr->data.picData.pData, newrectsize);
                                    close(osdsnapfd);
                                }
                            }
                        }
                    }
                }

                count ++;
                if (count >= maxOsdLayer) {
					int loop = 0;
					int yAvail_tmp = 0;
					lastLeftLine = lastLeftLine<=(frame->height-1)?lastLeftLine:(frame->height-1);
                    while (is_left) {
#if 0
                        int yAvail = (read_reg_32_addr(framePriv->valid_lines_reg_addr) >> 16) - 1;
						if ((0 == yAvail) || (yAvail_tmp > yAvail)) {
							IMP_LOG_WARN(TAG, "OSD in bottom part time warning yAvail = %d, yAvail_tmp = %d\n",
									yAvail, yAvail_tmp);
							break;
						}
						yAvail_tmp = yAvail;
                        if (lastLeftLine > yAvail) {
                            int diffLine = lastLeftLine - yAvail > 1 ? lastLeftLine - yAvail : 2;
                            usleep(diffLine * 6);
							if (loop++ > 100) {
								IMP_LOG_ERR(TAG, "OSD wait too long yAvail = %d, lastLeftLine = %d, frame width = %d, frame height = %d\n",
										yAvail, lastLeftLine, frame->width, frame->height);
								loop = 0;
							}
                        } else {
                            break;
                        }
#endif
                    }

					if (ret = ipu_osd(&ipu_osdp) != 0) {
                        IMP_LOG_ERR(TAG, "ipu: ipu_osd error ret = %d\n", ret);
                    }
					memset(&ipu_osdp, 0, sizeof(ipu_osdp));
                    count = 0;
                }
			}
		}
	}
	if (count != 0) {
		int loop = 0;
		int yAvail_tmp = 0;
		lastLeftLine = lastLeftLine<=(frame->height-1)?lastLeftLine:(frame->height-1);
        while (is_left) {
#if 0
            int yAvail = (read_reg_32_addr(framePriv->valid_lines_reg_addr) >> 16) - 1;
			if ((0 == yAvail) || (yAvail_tmp > yAvail)) {
				IMP_LOG_WARN(TAG, "OSD in bottom part time warning yAvail = %d, yAvail_tmp = %d\n",
						yAvail, yAvail_tmp);
				break;
			}
			yAvail_tmp = yAvail;
#ifdef DEBUG_FAST_FRAME
            IMP_LOG_INFO(TAG, "##### %s,%d, is_left=%d, frame_timestamp=%lld, frame_valid_lines = %u, frame_real_valid_lines = %d, lastLeftLine=%d\n",
                    __func__, __LINE__, is_left, frame->timeStamp, ((IMPFrameInfoPriv*)(frame->priv))->frame_valid_lines,
                    yAvail, lastLeftLine);
#endif
            if (lastLeftLine > yAvail) {
                int diffLine = lastLeftLine - yAvail > 1 ? lastLeftLine - yAvail : 2;
                usleep(diffLine * 6);
				if (loop++ > 100) {
					IMP_LOG_ERR(TAG, "OSD wait too long yAvail = %d, lastLeftLine = %d, frame width = %d, frame height = %d\n",
							yAvail, lastLeftLine, frame->width, frame->height);
					loop = 0;
				}
            } else {
                break;
            }
#endif
        }
		if ((ret = ipu_osd(&ipu_osdp)) != 0) {
			IMP_LOG_ERR(TAG, "ipu: ipu_osd error ret = %d\n", ret);
		}
        memset(&ipu_osdp, 0, sizeof(ipu_osdp));
	}

	return 0;
}

static int osd_getregionLuma(IMPFrameInfo *frame, IMPOSDRgnAttr *prAttr)
{
#if 0
	IMP_LOG_ERR(TAG, "rAttr.fontData.istimestamp = %d, \
			rAttr.fontData.invertColorSwitch = %d, \
			rAttr.fontData.luminance = %d, \
			rAttr.rect.p0.x = %d, rAttr.rect.p0.y = %d, \
			frame->index = %d, frame->width = %d, frame.virAddr = %d, \
			prAttr->fontData.data.fontHeight = %d, \
			prAttr->fontData.data.fontWidth = %d\n",
			prAttr->fontData.istimestamp,
			prAttr->fontData.invertColorSwitch,
			prAttr->fontData.luminance,
			prAttr->rect.p0.x, prAttr->rect.p0.y,
			frame->index, frame->width, frame->virAddr,
			prAttr->fontData.data.fontHeight,
			prAttr->fontData.data.fontWidth);
#endif
	unsigned int y_num_refer = prAttr->fontData.luminance;
	if (y_num_refer < 0 || y_num_refer > 255)
		y_num_refer = 200;

	if (prAttr->type != OSD_REG_BITMAP && prAttr->type != OSD_REG_PIC && prAttr->type != OSD_REG_PIC_RMEM) {
		IMP_LOG_ERR(TAG, "rAttr type is not equal OSD_REG_BITMAP/OSD_REG_PIC/OSD_REG_PIC_RMEM\n");
		return -1;
	}

	if (prAttr->fontData.length > (sizeof(prAttr->fontData.colType) / sizeof(prAttr->fontData.colType[0])))
	{
		IMP_LOG_DBG(TAG, "font length too large, length = %d, array length = %d\n",
				prAttr->fontData.length,
				(sizeof(prAttr->fontData.colType) / sizeof(prAttr->fontData.colType[0])));
		return -1;
	}
	int frame_width = frame->width;
	int font_width = prAttr->fontData.data.fontWidth;
	int font_height = prAttr->fontData.data.fontHeight;
	int start_x = prAttr->rect.p0.x;
	int start_y = prAttr->rect.p0.y;
	int y_num = 0, y_sum = 0;
	int current_x = 0, current_y = 0;
	int j = 0, a = 0, b = 0;
	for (j = 0; j <= prAttr->fontData.length; j++) {
		for(a = 0; a < font_height; a+=2) {
			for(b = 0; b < font_width; b+=2) {
				current_x = (start_x + j * font_width + b + 1) & ~1;
				current_y = (start_y + a + 1) & ~1;
				y_sum += *(volatile unsigned char*)(((unsigned char*)frame->virAddr) + current_y * frame_width + current_x);
			}
		}
		y_num = y_sum / (font_width * font_height / 2 / 2);
		if (y_num > y_num_refer) {
			prAttr->fontData.colType[j] = 1;
		} else {
			prAttr->fontData.colType[j] = 0;
		}
#if 0
		IMP_LOG_DBG(TAG, "fontnum = [%d], [%d]-[%d], y_num = %d\n", j, current_x, current_y, y_num);
#endif
		y_sum = 0;
	}

	return 0;
}

/**
 * 将osd_process抽出来作为一个独立的函数，是为了在帧下半部分再画剩余的图形
 * 用is_left来表示是上半部分还是下半部分
 * is_left == 0 表示上半部分， is_left == 1 表示下半部分
 */
static int osd_process(Group *group, IMPFrameInfo *frame, int is_left)
{
	Device *dev = get_device_of_group(group);
	IMPOsd *osd = (IMPOsd *)device_pri(dev);
	IMPOsdGroup *grp = &osd->group[group->group_index];

	static uint32_t u32cnt = 0;
	sem_wait(&osd->semRgnList);
	if (grp->is_work) {
		IMPOsdGrpRgnNode *grnode = grp->busygrlist.head;
		IMPOsdGrpRgnNode *grnode_tmp = NULL;
		IMPOsdGrpRgnNode *grnode_layer = grp->busygrlist.head;
		IMPOsdRgnNode *rnode = NULL;
		IMPOSDRgnAttrFifoData *fifodata0 = NULL;
		IMPOSDRgnAttrFifoData *fifodata1 = NULL;
		uint64_t ts0 = 0;
		uint64_t ts1 = 0;
		uint64_t fts = 0;

		while (grnode != NULL) {
			grnode_tmp = grnode;
			grnode = grnode->next;
			rnode = &osd->rnode[grnode_tmp->grAttrIndex];
			IMPOSDRgnAttr *rAttr = &rnode->rAttr;
			IMPOSDGrpRgnAttr *grAttr = &grnode_tmp->grAttr;
            IMPOSDHalfStatus *grHalfStatus = grnode_tmp->grHalfStatus;
retry:
			if (NULL != rnode->attrfifo) {
				int ret = -1;
				ret = fifo_pre_get_ptr(rnode->attrfifo, 0, (uint32_t**)(&fifodata0));
				if (0 == ret) {
					ts0 = fifodata0->ts.ts;
				} else {
					fifodata0 = NULL;
				}
				ret = fifo_pre_get_ptr(rnode->attrfifo, 1, (uint32_t**)(&fifodata1));
				if (0 == ret) {
					ts1 = fifodata1->ts.ts;
				} else {
					fifodata1 = NULL;
				}
				fts = frame->timeStamp;
				if (NULL == fifodata0) {
					//IMP_LOG_ERR(TAG, "err: %s,%d\n", __func__, __LINE__);
					continue;
				} else if (NULL == fifodata1){
					if (fts < ts0) {
						continue;
					} else {
						rAttr = &fifodata0->attr;
					}
				} else {
					if (fts < ts0) {
						continue;
					} else if (fts < ts1) {
						rAttr = &fifodata0->attr;
					} else {
						fifo_get(rnode->attrfifo, NULL);
						goto retry;
					}
				}
			}

			if(rAttr->fontData.invertColorSwitch) {
				osd_getregionLuma(frame, rAttr);
			}

			if (grnode_tmp->grAttr.show) {
				switch (rAttr->type) {
					case OSD_REG_INV:
						break;
					case OSD_REG_HORIZONTAL_LINE:
					case OSD_REG_VERTICAL_LINE:
						osd_draw_line(frame, rAttr, grAttr, &(grHalfStatus[0]), is_left);
						break;
					case OSD_REG_RECT:
						osd_draw_rect(frame, rAttr, grAttr, grHalfStatus, is_left);
						break;
					case OSD_REG_BITMAP:
						osd_draw_bitmap(frame, rAttr, grAttr, &(grHalfStatus[0]), is_left);
						break;
					case OSD_REG_SLASH:
						osd_draw_line(frame, rAttr, grAttr, &(grHalfStatus[0]), is_left);
						break;
					case OSD_REG_MOSAIC:
						if(group->group_index == 0 && frame->width == rAttr->mosaicAttr.frame_width)
							IMP_OSD_SetMosaic((unsigned char*)frame->virAddr, &rAttr->mosaicAttr);
						break;
					case OSD_REG_COVER:
					case OSD_REG_PIC:
					case OSD_REG_PIC_RMEM:
					case OSD_REG_FOUR_CORNER_RECT:
				//		osd_draw_cover_pic(frame, &rnode->rAttr, &grnode_tmp->grAttr);
						break;
				}
			}
		}
		OSD_Draw_Layer_Cover_Pic_RectLine(frame, grnode_layer, osd, is_left);
	}
	sem_post(&osd->semRgnList);
}

static int osd_update_left(Group *group, IMPFrameInfo *frame)
{
	Device *dev = get_device_of_group(group);
	IMPOsd *osd = (IMPOsd *)device_pri(dev);
	IMPOsdGroup *grp = &osd->group[group->group_index];

    if (!(grp->is_left_prio_modified)) {
        pthread_t tid = pthread_self();
        struct sched_param sched_param = {.sched_priority = 50};
        int policy = SCHED_RR;
        pthread_setschedparam(tid, policy, &sched_param);
        grp->is_left_prio_modified = 1;
    }
    VBMUnlockFrameByPaddr(frame->phyAddr);

    return 0;
}

static int osd_update(Group *group, IMPFrameInfo *frame)
{
	int i;

    osd_process(group, frame, 0);

	for (i = 0; i < group->module->num_of_observer; i++){
		group->for_output_data[i] = frame;
		if (i > 0){
			//VBMLockFrame(frame);
			VBMLockFrameByPaddr(frame->phyAddr);
		}
	}

	return 0;
}

int IMP_OSD_SetMosaic(unsigned char *frame_virAddr, IMPOSDMosaicAttr *mosaicAttr)
{
	int frame_width = mosaicAttr->frame_width;
	int frame_height = mosaicAttr->frame_height;
	int mosaic_width = mosaicAttr->mosaic_width;
	int mosaic_height = mosaicAttr->mosaic_height;
	int x = mosaicAttr->x;
	int y = mosaicAttr->y;
	int mosaic_min_size = mosaicAttr->mosaic_min_size;

	int XA = 0, YA = 0, i = 0, j = 0;
	unsigned int ybegin = y * frame_width + x, uvbegin = frame_width * frame_height + y / 2 * frame_width + x;
	if(frame_width % 2 != 0
			|| frame_height % 2 != 0
			|| mosaic_width % 2 != 0
			|| mosaic_height % 2 != 0
			|| x % 2 != 0
			|| y % 2 != 0
			|| x + mosaic_width > frame_width
			|| y + mosaic_height > frame_height)
	{
		IMP_LOG_ERR(TAG, "err: %s,%d, mosaic data error\n", __func__, __LINE__);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}

	for(i = 0; i < mosaic_width; i++) {
		if(i % mosaic_min_size == 0)
			XA = i;
		for(j = 0; j < mosaic_height; j++) {
			if(j % mosaic_min_size == 0)
				YA = j;
			frame_virAddr[ybegin + i + j * frame_width] = frame_virAddr[ybegin + XA + YA * frame_width];				//Y
			/*
			if (j < mosaic_height / 2)
			{
				if(i % 2)
					frame_virAddr[uvbegin + i + j * frame_width] = frame_virAddr[uvbegin + XA + YA * frame_width + 1];	//V
				else
					frame_virAddr[uvbegin + i + j * frame_width] = frame_virAddr[uvbegin + XA + YA * frame_width];		//U
			}
			*/
		}
	}

	return 0;
}

int IMP_OSD_CreateGroup(int grpNum)
{
	int i = 0;
	if (grpNum >= NR_MAX_OSD_GROUPS) {
		IMP_LOG_ERR(TAG, "func:%s, invalidate grpNum:%d\n", __func__, grpNum);
		return IMP_ERR_OSD_CHNID;
	}

	IMPOsd *osd = getOsd();
	if (osd == NULL) {
		IMP_LOG_ERR(TAG, "func:%s, OSD device hasn't been created\n", __func__);
		return IMP_ERR_OSD_UNEXIST;
	}

	Device *dev = osd->device;
	char grp_name[MAX_MODULE_NAME_LEN];

	sprintf(grp_name, "%s-%d", dev->name, grpNum);
	Group *grp = create_group(DEV_ID_OSD, grpNum, grp_name, osd_update);
	if (grp == NULL) {
		IMP_LOG_ERR(TAG, "create_group %s failed\n", grp_name);
		goto err_create_group;
	}

	for (i = 0; i < NR_MAX_OSD_REGION; i++) {
		osd->group[grpNum].grnode[i].grAttrIndex = i;
		osd->group[grpNum].grnode[i].grAttr.layer = 0;
	}

	grp->device = dev;
	grp->nr_outputs = NR_MAX_OUTPUT_IN_GROUP;
	dev->groups[grpNum] = grp;
	osd->group[grpNum].index = grpNum;

	IMP_LOG_DBG(TAG, "[%s][%d]group%d\n",__func__,__LINE__, grpNum);

	return 0;

err_create_group:
	return IMP_ERR_OSD_RESOURCE_REQUEST;
}

int IMP_OSD_DestroyGroup(int grpNum)
{
	IMP_LOG_DBG(TAG, "[%s][%d]group:%d\n",__func__,__LINE__,grpNum);

	int i = 0;

	if (grpNum >= NR_MAX_OSD_GROUPS) {
		IMP_LOG_ERR(TAG, "func:%s, invalidate grpNum:%d\n", __func__, grpNum);
		return IMP_ERR_OSD_CHNID;
	}

	IMPOsd *osd = getOsd();

	Device *dev = osd->device;
	Group *grp = dev->groups[grpNum];
	if (grp == NULL) {
		IMP_LOG_ERR(TAG, "Group-%d is not created\n");
		return IMP_ERR_OSD_UNEXIST;
	}

	destroy_group(grp, DEV_ID_OSD);
	dev->groups[grpNum] = NULL;
    osd->group[grpNum].is_left_prio_modified = 0;

	for (i = 0; i < NR_MAX_OSD_GROUPS; i++) {
		if (1 == osd->group[i].is_work)	{
			break;
		}
	}
	if (NR_MAX_OSD_GROUPS == i) {
		ipu_deinit();
	}
	return 0;
}

int IMP_OSD_AttachToGroup(IMPCell *from, IMPCell *to)
{
	if (system_attach(from, to) < 0) {
		IMP_LOG_ERR(TAG, "%s (device,group,output)=(%d,%d,%d)->(%d,%d,%d) failed\n",
				__func__, from->deviceID, from->groupID, from->outputID,
				to->deviceID, to->groupID, to->outputID);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}

	return 0;
}

void OSD_RmemSetNewAddr(IMPOsdRgnNode * pRgnheadnode,mem_node_t* pmheadnode)
{
    IMPOsdRgnNode * pnode = NULL;
    mem_node_t*   pmemnode = NULL;
    pnode = pRgnheadnode;
    pmemnode = pmheadnode;
    while(pmemnode){
        while(pnode){
            if(pnode->rAttr.data.picData.pData == pmemnode->oldaddr){
                pnode->rAttr.data.picData.pData = pmemnode->addr;
                pmemnode->oldaddr = pmemnode->addr;
                break;
            }
            pnode = pnode->next;
        }
        pmemnode = pmemnode->next;
    }
    return ;
}

int IMP_OSD_RgnCreate_Query(IMPRgnHandle handle,IMPOSDRgnCreateStat *pstStatus)
{
    if(NULL == pstStatus){
        IMP_LOG_ERR(TAG, "pstStatus is NULL\n");
        return IMP_ERR_OSD_NULL_PTR;
    }
    if (handle >= NR_MAX_OSD_REGION) {
        IMP_LOG_ERR(TAG, "%s, Invalidate IMPRgnHandle\n", __func__);
        return IMP_ERR_OSD_PARAM;
    }
    IMPOsd *osd = getOsd();
    sem_wait(&osd->semRgnList);

    IMPOsdRgnNode *prnode = &osd->rnode[handle];
    pstStatus->status = prnode->status;

    sem_post(&osd->semRgnList);
    return 0;
}

int IMP_OSD_RgnRegister_Query(IMPRgnHandle handle,int grpNum,IMPOSDRgnRegisterStat *pstStatus)
{
    if(NULL == pstStatus){
        IMP_LOG_ERR(TAG, "pstStatus is NULL\n");
        return IMP_ERR_OSD_NULL_PTR;
    }
    if (handle >= NR_MAX_OSD_REGION) {
        IMP_LOG_ERR(TAG, "%s, Invalidate IMPRgnHandle\n", __func__);
        return IMP_ERR_OSD_PARAM;
    }
    if (grpNum >= NR_MAX_OSD_GROUPS) {
        IMP_LOG_ERR(TAG, "%s, Invalidate Group Num\n", __func__);
        return IMP_ERR_OSD_CHNID;
    }

    IMPOsd *osd = getOsd();
    sem_wait(&osd->semRgnList);

    IMPOsdGrpRgnNode *pgrnode = &osd->group[grpNum].grnode[handle];
    pstStatus->status = pgrnode->status;

    sem_post(&osd->semRgnList);
    return 0;
}

IMPRgnHandle IMP_OSD_CreateRgn(IMPOSDRgnAttr *prAttr)
{
	IMPOsdRgnNode *prnode;
	void *prData = NULL;
	int rgnsize = 0;

	IMPOsd *osd = getOsd();

	sem_wait(&osd->semRgnList);
	if (osd->freerlist.head == NULL) {
		IMP_LOG_ERR(TAG, "osd->freerlist is empty\n");
		goto err_freerlist_empty;
	}
	if (prAttr && ((prAttr->type == OSD_REG_BITMAP) || (prAttr->type == OSD_REG_PIC) || (prAttr->type == OSD_REG_PIC_RMEM))) {
		rgnsize = osd_rgnsize(prAttr);
        if (prAttr->type == OSD_REG_PIC_RMEM) {
            prData = OSD_mem_alloc(osd->osd_mem, rgnsize);
            if (prData == NULL) {
                IMP_LOG_ERR(TAG, "mem alloc prData failed\n");
                goto err_calloc_prData;
            }
        } else {
            prData = calloc(1, rgnsize);
            if (prData == NULL) {
                IMP_LOG_ERR(TAG, "calloc prData failed\n");
                goto err_calloc_prData;
            }
        }
	}
	prnode = osd->freerlist.head;
	osd->freerlist.head = osd->freerlist.head->next;
	if (osd->freerlist.head == NULL) {
		osd->freerlist.tail = NULL;
	} else {
		osd->freerlist.head->prev = NULL;
	}

	if (osd->busyrlist.head == NULL) {
		osd->busyrlist.head = osd->busyrlist.tail = prnode;
		osd->busyrlist.tail->prev = NULL;
		osd->busyrlist.tail->next = NULL;
	} else {
		osd->busyrlist.tail->next = prnode;
		osd->busyrlist.tail->next->prev = osd->busyrlist.tail;
		osd->busyrlist.tail = osd->busyrlist.tail->next;
		osd->busyrlist.tail->next = NULL;
	}
	prnode->status = IMP_OSD_RGN_BUSY;
	if (prAttr) {
		if ((prAttr->type == OSD_REG_BITMAP) && prAttr->data.bitmapData) {
			memcpy(prData, prAttr->data.bitmapData, rgnsize);
		} else if (((prAttr->type == OSD_REG_PIC)||(prAttr->type == OSD_REG_PIC_RMEM)) && prAttr->data.picData.pData) {
			if (IS_SOC_SERIES(T10)) {
				if (prAttr->fmt == PIX_FMT_RGB555LE) {
					Convert1555To8888(prData, prAttr->data.picData.pData, rgnsize);
				} else if (prAttr->fmt == PIX_FMT_BGRA) {
					memcpy(prData, prAttr->data.picData.pData, rgnsize);
				}
			} else {
					memcpy(prData, prAttr->data.picData.pData, rgnsize);
			}
		}
        /*OSD_REG_PIC 是通过分时复用内存进行管理的
         *OSD_REG_PIC_RMEM 是通过rnode节点区分，需要进行内存的整理
         *因此加以区分*/
		memcpy(&prnode->rAttr, prAttr, sizeof(IMPOSDRgnAttr));
		if (prAttr->type == OSD_REG_BITMAP) {
			prnode->rAttr.data.bitmapData = prData;
		} else if (prAttr->type == OSD_REG_PIC) {
			prnode->rAttr.data.picData.pData = prData;
		} else if(prAttr->type == OSD_REG_PIC_RMEM){
            prnode->rAttr.data.picData.pData = prData; /*将节点地址空间赋值给结点*/
            /*地址回溯整理，需要加锁，因为已有semRgnList这把锁锁住，故这里没有新加锁*/
            OSD_RmemSetNewAddr(osd->busyrlist.head,osd->osd_mem->busy.head);
        }
	} else {
		memset(&prnode->rAttr, 0, sizeof(IMPOSDRgnAttr));
	}

	prnode->attrfifo = NULL;
	sem_post(&osd->semRgnList);

	return prnode->rAttrIndex;

err_freerlist_empty:
	free(prData);
	sem_post(&osd->semRgnList);
	return IMP_ERR_OSD_UNEXIST;
err_calloc_prData:
    free(prData);
	sem_post(&osd->semRgnList);
	return IMP_ERR_OSD_NOMEM;
}

void IMP_OSD_DestroyRgn(IMPRgnHandle handle)
{
	IMP_LOG_DBG(TAG, "[%s][%d]handle:%d\n",__func__,__LINE__,handle);

	IMPOsd *osd = getOsd();
	IMPOsdRgnNode *prnode = &osd->rnode[handle];
	sem_wait(&osd->semRgnList);
	if (prnode->status == IMP_OSD_RGN_BUSY && prnode->refcnt <= 0) {
		if (prnode != osd->busyrlist.head && prnode != osd->busyrlist.tail) {
			prnode->prev->next = prnode->next;
			prnode->next->prev = prnode->prev;
		} else if ((prnode == osd->busyrlist.head) && (prnode == osd->busyrlist.tail)) {
			osd->busyrlist.head = osd->busyrlist.tail = NULL;
		} else if ((prnode == osd->busyrlist.head) && (prnode != osd->busyrlist.tail)) {
			osd->busyrlist.head = osd->busyrlist.head->next;
			osd->busyrlist.head->prev = NULL;
		} else if ((prnode != osd->busyrlist.head) && (prnode == osd->busyrlist.tail)) {
			osd->busyrlist.tail = osd->busyrlist.tail->prev;
			osd->busyrlist.tail->next = NULL;
		}

		if (osd->freerlist.head == NULL) {
			osd->freerlist.head = osd->freerlist.tail = prnode;
			osd->freerlist.tail->prev = NULL;
			osd->freerlist.tail->next = NULL;
		} else {
			osd->freerlist.tail->next = prnode;
			osd->freerlist.tail->next->prev = osd->freerlist.tail;
			osd->freerlist.tail = osd->freerlist.tail->next;
			osd->freerlist.tail->next = NULL;
		}
		prnode->status = IMP_OSD_RGN_FREE;
		if ((prnode->rAttr.type == OSD_REG_BITMAP) && (prnode->rAttr.data.bitmapData != NULL)) {
			free(prnode->rAttr.data.bitmapData);
		} else if ((prnode->rAttr.type == OSD_REG_PIC) && (prnode->rAttr.data.picData.pData != NULL)) {
			free(prnode->rAttr.data.picData.pData);
		} else if ((prnode->rAttr.type == OSD_REG_PIC_RMEM) && (prnode->rAttr.data.picData.pData != NULL)) {
            OSD_mem_free(osd->osd_mem, prnode->rAttr.data.picData.pData);
            //OSD_mem_dump(osd->osd_mem);
		}

		if (NULL != prnode->attrfifo)
			fifo_free(prnode->attrfifo);

		memset(&prnode->rAttr, 0, sizeof(IMPOSDRgnAttr));
	}

	sem_post(&osd->semRgnList);
}

int IMP_OSD_RegisterRgn(IMPRgnHandle handle, int grpNum, IMPOSDGrpRgnAttr *pgrAttr)
{
	if (handle >= NR_MAX_OSD_REGION) {
		IMP_LOG_ERR(TAG, "%s, Invalidate IMPRgnHandle\n", __func__);
		return IMP_ERR_OSD_PARAM;
	}
	if (grpNum >= NR_MAX_OSD_GROUPS) {
		IMP_LOG_ERR(TAG, "%s, Invalidate Group Num\n", __func__);
		return IMP_ERR_OSD_CHNID;
	}
	IMPOsd *osd = getOsd();
	IMPOsdGrpRgnNode *pgrnode = &osd->group[grpNum].grnode[handle];

	sem_wait(&osd->registerlock);
	if (pgrnode->status == IMP_OSD_RGN_BUSY) {
		sem_post(&osd->registerlock);
		IMP_LOG_ERR(TAG, "the region %d has been registed to group %d\n", handle, grpNum);
		return IMP_ERR_OSD_NOT_CONFIG;
	}
	if (osd->group[grpNum].busygrlist.head == NULL) {
		osd->group[grpNum].busygrlist.head = osd->group[grpNum].busygrlist.tail = pgrnode;
		osd->group[grpNum].busygrlist.tail->prev = NULL;
		osd->group[grpNum].busygrlist.tail->next = NULL;
	} else {
		osd->group[grpNum].busygrlist.tail->next = pgrnode;
		osd->group[grpNum].busygrlist.tail->next->prev = osd->group[grpNum].busygrlist.tail;
		osd->group[grpNum].busygrlist.tail = osd->group[grpNum].busygrlist.tail->next;
		osd->group[grpNum].busygrlist.tail->next = NULL;
	}
	pgrnode->status = IMP_OSD_RGN_BUSY;
	osd->rnode[handle].refcnt++;
	sem_post(&osd->registerlock);
	if (pgrAttr) {
		memcpy(&pgrnode->grAttr, pgrAttr, sizeof(IMPOSDGrpRgnAttr));
	}

	return 0;
}

int IMP_OSD_UnRegisterRgn(IMPRgnHandle handle, int grpNum)
{
	if (handle >= NR_MAX_OSD_REGION) {
		IMP_LOG_ERR(TAG, "%s, Invalidate IMPRgnHandle\n", __func__);
		return IMP_ERR_OSD_PARAM;
	}
	if (grpNum >= NR_MAX_OSD_GROUPS) {
		IMP_LOG_ERR(TAG, "%s, Invalidate Group Num\n", __func__);
		return IMP_ERR_OSD_CHNID;
	}
	IMPOsd *osd = getOsd();
	IMPOsdGrpRgnNode *pgrnode = &osd->group[grpNum].grnode[handle];

	sem_wait(&osd->registerlock);
	if (pgrnode->status == IMP_OSD_RGN_FREE) {
		sem_post(&osd->registerlock);
		IMP_LOG_ERR(TAG, "the region %d hasn't been registed to group %d\n", handle, grpNum);
		return IMP_ERR_OSD_NOT_CONFIG;
	}
	IMPOsdGrpRgnList *list = &osd->group[grpNum].busygrlist;
	if  (pgrnode != list->head && pgrnode != list->tail) {
		pgrnode->prev->next = pgrnode->next;
		pgrnode->next->prev = pgrnode->prev;
	} else if ((pgrnode == list->head) && (pgrnode == list->tail)) {
		list->head = list->tail = NULL;
	} else if ((pgrnode == list->head) && (pgrnode != list->tail)) {
		list->head = list->head->next;
		list->head->prev = NULL;
	} else if ((pgrnode != list->head) && (pgrnode == list->tail)) {
		list->tail = list->tail->prev;
		list->tail->next = NULL;
	}

	pgrnode->status = IMP_OSD_RGN_FREE;
	osd->rnode[handle].refcnt--;
	sem_post(&osd->registerlock);
	memset(&pgrnode->grAttr, 0, sizeof(IMPOSDGrpRgnAttr));

	return 0;
}

static inline unsigned int ARGB1555toARGB8888(unsigned short c)
{
	const unsigned int a = c&0x8000, r = c&0x7C00, g = c&0x03E0, b = c&0x1F;
	const unsigned int rgb = (r << 9) | (g << 6) | (b << 3);
	return (a*0x1FE00) | rgb | ((rgb >> 5) & 0x070707);
}

static inline unsigned short ARGB8888toARGB1555(unsigned int c)
{
	const unsigned short a = (c&0xFF000000 >> 24), r = (c&0x00FF0000 >> 16), g = (c&0x0000FF00 >> 8), b = (c&0x000000FF);
	const unsigned short rgb = ((r >> 3) << 10) | ((g >> 3)<< 5) | (b >> 3);
	return ((a >> 7) <<15 | rgb );
}

static int Convert1555To8888(void *pData, void *picData, int newrectsize)
{
	uint16_t *srcData = (uint16_t *)(picData);
	uint32_t *flagData = (uint32_t *)pData;
	unsigned int destData = 0;
//	uint32_t midData32=0;
	uint16_t midData16=0;
	int i = 0;
	if (pData != NULL && picData != NULL) {
		for(i = 0; i < newrectsize; i+=4){
	//		midData32 = (uint8_t)((*srcData) << 24) | (uint8_t)((*(srcData++))  << 16) | (uint8_t)((*(srcData++))  << 8) | (uint8_t)(*(srcData++));
	//		midData16 = ARGB8888toARGB1555(midData32);
			midData16 = *(uint16_t *)srcData;
			destData = ARGB1555toARGB8888(midData16);
			*flagData = destData;
			flagData ++;
			srcData ++;
		}
	} else {
		IMP_LOG_ERR(TAG, "%s,Convert1555To8888  Data is NULL\n", __func__);
		return IMP_ERR_OSD_NULL_PTR;
	}
	return 0;
}

int IMP_OSD_UpdateRgnAttrData(IMPRgnHandle handle, IMPOSDRgnAttrData *prAttrData)
{
	if (handle >= NR_MAX_OSD_REGION) {
		IMP_LOG_ERR(TAG, "%s, Invalidate IMPRgnHandle\n", __func__);
		return IMP_ERR_OSD_PARAM;
	}
	IMPOsd *osd = getOsd();
	if (osd->rnode[handle].status == IMP_OSD_RGN_FREE) {
		IMP_LOG_ERR(TAG, "%s, the region %d hasn't been created\n", __func__, handle);
		return IMP_ERR_OSD_UNEXIST;
	}

	sem_wait(&osd->semRgnList);
	IMPOSDRgnAttr *prAttr = &osd->rnode[handle].rAttr;
	if ((prAttr->type == OSD_REG_BITMAP) && prAttr->data.bitmapData) {
		memcpy(prAttr->data.bitmapData, prAttrData->bitmapData, osd_rgnsize(prAttr));
	} else if (((prAttr->type == OSD_REG_PIC)||(prAttr->type == OSD_REG_PIC_RMEM)) && prAttr->data.picData.pData) {
		if (IS_SOC_SERIES(T10)) {
			if (prAttr->fmt == PIX_FMT_RGB555LE) {
				Convert1555To8888(prAttr->data.picData.pData, prAttrData->picData.pData, osd_rgnsize(prAttr));
			} else if (prAttr->fmt == PIX_FMT_BGRA) {
				memcpy(prAttr->data.picData.pData, prAttrData->picData.pData, osd_rgnsize(prAttr));
			}
		} else {
			memcpy(prAttr->data.picData.pData, prAttrData->picData.pData, osd_rgnsize(prAttr));
		}
	} else {
		memcpy(&prAttr->data, prAttrData, sizeof(IMPOSDRgnAttrData));
	}
	sem_post(&osd->semRgnList);

	return 0;
}

int IMP_OSD_GetRgnAttr(IMPRgnHandle handle, IMPOSDRgnAttr *prAttr)
{
	if (handle >= NR_MAX_OSD_REGION) {
		IMP_LOG_ERR(TAG, "%s, Invalidate IMPRgnHandle\n", __func__);
		return IMP_ERR_OSD_PARAM;
	}
	IMPOsd *osd = getOsd();
	if (osd->rnode[handle].status == IMP_OSD_RGN_FREE) {
		IMP_LOG_ERR(TAG, "%s, the region %d hasn't been created\n", __func__, handle);
		return IMP_ERR_OSD_UNEXIST;
	}
	memcpy(prAttr, &osd->rnode[handle].rAttr, sizeof(IMPOSDRgnAttr));

	return 0;
}

static int osd_set_rattr_bitmap(IMPOSDRgnAttr *prAttr, IMPOSDRgnAttr *new_prAttr)
{
	void *pbitmapData = NULL;
	int newrectsize = osd_rgnsize(new_prAttr);

	/* Get the bitmapdata space */
	if (prAttr->type == OSD_REG_BITMAP) {
		if ((prAttr->data.bitmapData == NULL) || (osd_rgnsize(prAttr) != newrectsize)) {
			if ((prAttr->data.bitmapData = realloc(prAttr->data.bitmapData, newrectsize)) == NULL) {
				IMP_LOG_ERR(TAG, "%s:malloc pbitmapData size=%d failed\n", __func__, __LINE__, newrectsize);
				goto err_malloc_bitmapData;
			}
		}
		pbitmapData = prAttr->data.bitmapData;
	} else if (prAttr->type == OSD_REG_PIC) {
		if ((prAttr->data.picData.pData == NULL) || (osd_rgnsize(prAttr) != newrectsize)) {
			if ((prAttr->data.picData.pData = realloc(prAttr->data.picData.pData, newrectsize)) == NULL) {
				IMP_LOG_ERR(TAG, "%s:malloc pbitmapData size=%d failed\n", __func__, __LINE__, newrectsize);
				goto err_malloc_bitmapData;
			}
		}
		pbitmapData = prAttr->data.picData.pData;
    } else if (prAttr->type == OSD_REG_PIC_RMEM) {
        IMP_LOG_ERR(TAG, "%s:err_pic_rmem_change_to_bitmap\n", __func__, __LINE__);
        goto err_pic_rmem_change_to_bitmap;
	} else {
		if ((pbitmapData = malloc(newrectsize)) == NULL) {
			IMP_LOG_ERR(TAG, "%s:malloc pbitmapData size=%d failed\n", __func__, __LINE__, newrectsize);
			goto err_malloc_bitmapData;
		}
	}

	if (new_prAttr->data.bitmapData) {
		memcpy(pbitmapData, new_prAttr->data.bitmapData, newrectsize);
	} else {
		memset(pbitmapData, 0, newrectsize);
	}
	memcpy(prAttr, new_prAttr, sizeof(IMPOSDRgnAttr));
	prAttr->data.bitmapData = pbitmapData;

	return 0;

err_malloc_bitmapData:
	return IMP_ERR_OSD_NOMEM;
err_pic_rmem_change_to_bitmap:

	return IMP_ERR_OSD_NOT_SUPPORT;
}

static int osd_set_rattr_pic(IMPOSDRgnAttr *prAttr, IMPOSDRgnAttr *new_prAttr)
{
	void *pData = NULL;
	int newrectsize = osd_rgnsize(new_prAttr);
	IMPOsd *osd = getOsd();

	/* Get the pData space */
	if (prAttr->type == OSD_REG_BITMAP) {
		if ((prAttr->data.bitmapData == NULL) || (osd_rgnsize(prAttr) != (newrectsize))) {
			if ((prAttr->data.bitmapData = realloc(prAttr->data.bitmapData, newrectsize)) == NULL) {
				IMP_LOG_ERR(TAG, "%s,%d:malloc pData size=%d failed\n", __func__, __LINE__, newrectsize);
				goto err_malloc_pData;
			}
		}
		pData = prAttr->data.bitmapData;
	} else if (prAttr->type == OSD_REG_PIC) {
		if ((prAttr->data.picData.pData == NULL) || (osd_rgnsize(prAttr) != newrectsize)) {
			pData = prAttr->data.picData.pData == NULL ? NULL : prAttr->data.picData.pData;
			if ((pData = realloc(pData, newrectsize)) == NULL) {
				IMP_LOG_ERR(TAG, "%s,%d:malloc pData size=%d failed\n", __func__, __LINE__, newrectsize);
				goto err_malloc_pData;
			}
		} else {
			pData = prAttr->data.picData.pData;
		}
    } else if ((new_prAttr->type == OSD_REG_PIC_RMEM)) {

        if (prAttr->type == OSD_REG_INV) {
            if ((pData = OSD_mem_alloc(osd->osd_mem, newrectsize)) == NULL) {
                IMP_LOG_ERR(TAG, "%s,%d:malloc pData size=%d failed\n", __func__, __LINE__, newrectsize);
                goto err_malloc_pData;
            }
            //OSD_mem_dump(osd->osd_mem);
        } else if ((prAttr->type == OSD_REG_PIC_RMEM)&&(osd_rgnsize(prAttr) == newrectsize)){
			pData = prAttr->data.picData.pData;
        } else {
            IMP_LOG_ERR(TAG, "%s,%d:err_set_pic_rmem_attr\n", __func__, __LINE__);
            goto err_set_pic_rmem_attr;
        }
    } else {
        if ((pData = malloc(newrectsize)) == NULL) {
            IMP_LOG_ERR(TAG, "%s,%d:malloc pData size=%d failed\n", __func__, __LINE__, newrectsize);
            goto err_malloc_pData;
        }
    }

	if (new_prAttr->data.picData.pData) {
		if (!IS_SOC_SERIES(T10)) {
			memcpy(pData, new_prAttr->data.picData.pData, newrectsize);
		}
	} else {
		memset(pData, 0, newrectsize);
	}
	memcpy(prAttr, new_prAttr, sizeof(IMPOSDRgnAttr));
	prAttr->data.picData.pData = pData;
    /*地址回溯整理，只有在OSD_REG_PIC_REM模式下进行整理操作，最外层已经加了semRgnlist这把锁，故这里不再加锁*/
    if (new_prAttr->type == OSD_REG_PIC_RMEM) {
        OSD_RmemSetNewAddr(osd->busyrlist.head,osd->osd_mem->busy.head);
    }

	return 0;

err_set_pic_rmem_attr:
	return IMP_ERR_OSD_NOT_SUPPORT;
err_malloc_pData:
	return IMP_ERR_OSD_NOMEM;
}

static int osd_set_rattr_nbitmap_and_nopic(IMPOSDRgnAttr *prAttr, IMPOSDRgnAttr *new_prAttr)
{
	if ((prAttr->type == OSD_REG_BITMAP) && (prAttr->data.bitmapData != NULL)) {
		free(prAttr->data.bitmapData);
		prAttr->data.bitmapData = NULL;
	} else if ((prAttr->type == OSD_REG_PIC) && (prAttr->data.picData.pData != NULL)) {
		free(prAttr->data.picData.pData);
		prAttr->data.picData.pData = NULL;
    } else if (prAttr->type == OSD_REG_PIC_RMEM) {
        IMP_LOG_ERR(TAG, "%s:err_change_to_pic_rmem\n", __func__, __LINE__);
        goto err_change_to_pic_rmem;
    }

	memcpy(prAttr, new_prAttr, sizeof(IMPOSDRgnAttr));

	return 0;
err_change_to_pic_rmem:
    return IMP_ERR_OSD_NOT_SUPPORT;
}

int IMP_OSD_SetRgnAttr(IMPRgnHandle handle, IMPOSDRgnAttr *prAttr)
{
	int ret = 0;
	if (handle >= NR_MAX_OSD_REGION) {
		IMP_LOG_ERR(TAG, "%s, Invalidate IMPRgnHandle\n", __func__);
		return IMP_ERR_OSD_PARAM;
	}
	IMPOsd *osd = getOsd();
	if (osd->rnode[handle].status == IMP_OSD_RGN_FREE) {
		IMP_LOG_ERR(TAG, "%s, the region %d hasn't been created\n", __func__, handle);
		return IMP_ERR_OSD_UNEXIST;
	}
	sem_wait(&osd->semRgnList);
	if (prAttr->type == OSD_REG_BITMAP) {
		ret = osd_set_rattr_bitmap(&osd->rnode[handle].rAttr, prAttr);
	} else if ((prAttr->type == OSD_REG_PIC)||(prAttr->type == OSD_REG_PIC_RMEM)) {
		ret = osd_set_rattr_pic(&osd->rnode[handle].rAttr, prAttr);
	} else {
		ret = osd_set_rattr_nbitmap_and_nopic(&osd->rnode[handle].rAttr, prAttr);
	}
	sem_post(&osd->semRgnList);

	return ret;
}

int IMP_OSD_SetRgnAttrWithTimestamp(IMPRgnHandle handle, IMPOSDRgnAttr *prAttr, IMPOSDRgnTimestamp *prTs)
{
	int ret = 0;
	IMPOsdRgnNode *node;
	IMPOsd *osd = getOsd();
	IMPOSDRgnAttrFifoData fifodata;

	if ((prAttr->type != OSD_REG_RECT)&&((prAttr->type != OSD_REG_COVER))) {
		IMP_LOG_ERR(TAG, "%d, rgn with ts only support rect and cover\n", __LINE__);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}

	sem_wait(&osd->semRgnList);
	node = &osd->rnode[handle];
	if (NULL == node->attrfifo) {
		node->attrfifo = fifo_alloc(OSD_ATTR_FIFO_SIZE, sizeof(fifodata));
		if (NULL == node->attrfifo) {
			IMP_LOG_ERR(TAG, "%d, fifo_alloc failed\n", __LINE__);
			goto err;
		}
	}
	memcpy(&fifodata.attr, prAttr, sizeof(IMPOSDRgnAttr));
	memcpy(&fifodata.ts, prTs, sizeof(IMPOSDRgnTimestamp));
	ret = fifo_put(node->attrfifo, (uint32_t*)&fifodata);
	if (0 != ret) {
		IMP_LOG_ERR(TAG, "%d, fifo_put failed\n", __LINE__);
		goto err;
	}
	sem_post(&osd->semRgnList);

	ret = IMP_OSD_SetRgnAttr(handle, prAttr);
	if (0 != ret) {
		IMP_LOG_ERR(TAG, "%d, IMP_OSD_SetRgnAttr failed\n", __LINE__);
		return ret;
	}

	return ret;
err:
	sem_post(&osd->semRgnList);
	return IMP_ERR_OSD_NOMEM | IMP_ERR_OSD_NOT_SUPPORT;
}

int IMP_OSD_GetGrpRgnAttr(IMPRgnHandle handle, int grpNum, IMPOSDGrpRgnAttr *pgrAttr)
{
	if (handle >= NR_MAX_OSD_REGION) {
		IMP_LOG_ERR(TAG, "%s, Invalidate IMPRgnHandle\n", __func__);
		return IMP_ERR_OSD_PARAM;
	}

	if (grpNum >= NR_MAX_OSD_GROUPS) {
		IMP_LOG_ERR(TAG, "%s, Invalidate Group Num\n", __func__);
		return IMP_ERR_OSD_CHNID;
	}

	IMPOsd *osd = getOsd();
	IMPOsdGrpRgnNode *pgrnode = &osd->group[grpNum].grnode[handle];

	if (pgrnode->status == IMP_OSD_RGN_FREE) {
		IMP_LOG_ERR(TAG, "%s, the region %d hasn't been registed to group %d\n", __func__, handle, grpNum);
		return IMP_ERR_OSD_NOT_CONFIG;
	}

	memcpy(pgrAttr, &pgrnode->grAttr, sizeof(IMPOSDGrpRgnAttr));

	return 0;
}

int IMP_OSD_SetGrpRgnAttr(IMPRgnHandle handle, int grpNum, IMPOSDGrpRgnAttr *pgrAttr)
{
	if (handle >= NR_MAX_OSD_REGION) {
		IMP_LOG_ERR(TAG, "%s, Invalidate IMPRgnHandle\n", __func__);
		return IMP_ERR_OSD_PARAM;
	}

	if (grpNum >= NR_MAX_OSD_GROUPS) {
		IMP_LOG_ERR(TAG, "%s, Invalidate Group Num\n", __func__);
		return IMP_ERR_OSD_CHNID;
	}

	IMPOsd *osd = getOsd();
	IMPOsdGrpRgnNode *pgrnode = &osd->group[grpNum].grnode[handle];

	if (pgrnode->status == IMP_OSD_RGN_FREE) {
		IMP_LOG_ERR(TAG, "%s, the region %d hasn't been registed to group %d\n", __func__, handle, grpNum);
		return IMP_ERR_OSD_NOT_CONFIG;
	}

	memcpy(&pgrnode->grAttr, pgrAttr, sizeof(IMPOSDGrpRgnAttr));
#if 1   /*From small to large to sort the GroupRegion busygrlist*/
	sem_wait(&osd->registerlock);
	IMPOsdGrpRgnNode *flagGrnode = osd->group[grpNum].busygrlist.head;
	if (pgrnode == flagGrnode && pgrnode == osd->group[grpNum].busygrlist.tail) {
		;
	} else if (pgrnode == flagGrnode && pgrnode != osd->group[grpNum].busygrlist.tail) {     //pgrnode is head
		flagGrnode = flagGrnode->next;
		while (flagGrnode != NULL) {
			if (pgrnode->grAttr.layer >= flagGrnode->grAttr.layer) {
				if (flagGrnode->next != NULL) {
					if (pgrnode->grAttr.layer < flagGrnode->next->grAttr.layer) {
						if (osd->group[grpNum].busygrlist.head->next != NULL) {
							osd->group[grpNum].busygrlist.head = osd->group[grpNum].busygrlist.head->next;     //head = pgrnode->next
							osd->group[grpNum].busygrlist.head->prev = NULL;
						}
						flagGrnode->next->prev = pgrnode;
						pgrnode->next = flagGrnode->next;
						pgrnode->prev = flagGrnode;
						flagGrnode->next = pgrnode;
						break;
					}
				} else {
					if (osd->group[grpNum].busygrlist.head->next != NULL) {
						osd->group[grpNum].busygrlist.head = osd->group[grpNum].busygrlist.head->next;     //head = pgrnode->next
						osd->group[grpNum].busygrlist.head->prev = NULL;
					}
					flagGrnode->next = pgrnode;
					pgrnode->prev = flagGrnode;
					pgrnode->next = NULL;
					osd->group[grpNum].busygrlist.tail = pgrnode;
					break;
				}
			}
			flagGrnode = flagGrnode->next;
		}
	} else if (pgrnode != flagGrnode && pgrnode == osd->group[grpNum].busygrlist.tail) {
		while (flagGrnode != NULL) {
			if (pgrnode->grAttr.layer < flagGrnode->grAttr.layer) {
				if (flagGrnode->prev == NULL) {
					if (osd->group[grpNum].busygrlist.tail->prev != NULL) {
						osd->group[grpNum].busygrlist.tail = osd->group[grpNum].busygrlist.tail->prev;     //pgrnode is tail
						osd->group[grpNum].busygrlist.tail->next = NULL;
					}
					flagGrnode->prev = pgrnode;
					pgrnode->next = flagGrnode;
					pgrnode->prev = NULL;
					osd->group[grpNum].busygrlist.head = pgrnode;
					break;
				} else if (pgrnode->grAttr.layer >= flagGrnode->prev->grAttr.layer) {
					if (osd->group[grpNum].busygrlist.tail->prev != NULL) {
						osd->group[grpNum].busygrlist.tail = osd->group[grpNum].busygrlist.tail->prev;     //pgrnode is tail
						osd->group[grpNum].busygrlist.tail->next = NULL;
					}
					flagGrnode->prev->next = pgrnode;
					pgrnode->prev = flagGrnode->prev;
					pgrnode->next = flagGrnode;
					flagGrnode->prev = pgrnode;
					break;
				}
			}
			flagGrnode = flagGrnode->next;
		}
	} else if (pgrnode != flagGrnode && pgrnode != osd->group[grpNum].busygrlist.tail) {
		while (flagGrnode != NULL) {
			if (pgrnode->grAttr.layer >= flagGrnode->grAttr.layer && pgrnode != flagGrnode) {
				if (flagGrnode->next != NULL) {      //this is not tail!!!!
					if (pgrnode->grAttr.layer < flagGrnode->next->grAttr.layer) {
						pgrnode->next->prev = pgrnode->prev;
						pgrnode->prev->next = pgrnode->next;

						flagGrnode->next->prev = pgrnode;
						pgrnode->next = flagGrnode->next;
						pgrnode->prev = flagGrnode;
						flagGrnode->next = pgrnode;
						break;
					}
				} else {           //this is tail!!!!!
						pgrnode->next->prev = pgrnode->prev;
						pgrnode->prev->next = pgrnode->next;

					flagGrnode->next = pgrnode;
					pgrnode->prev = flagGrnode;
					pgrnode->next = NULL;
					osd->group[grpNum].busygrlist.tail = pgrnode;
					break;
				}
			} else if (pgrnode->grAttr.layer < flagGrnode->grAttr.layer) {
				if (flagGrnode->prev != NULL) {      //this is not head!!!!
					if (pgrnode->grAttr.layer >= flagGrnode->prev->grAttr.layer) {
							pgrnode->next->prev = pgrnode->prev;
							pgrnode->prev->next = pgrnode->next;

						pgrnode->next = flagGrnode;
						pgrnode->prev = flagGrnode->prev;
						flagGrnode->prev->next = pgrnode;
						flagGrnode->prev = pgrnode;
						break;
					}
				} else {           //this is head!!!!!
						pgrnode->next->prev = pgrnode->prev;
						pgrnode->prev->next = pgrnode->next;

					flagGrnode->prev = pgrnode;
					pgrnode->prev = NULL;
					pgrnode->next = flagGrnode;
					osd->group[grpNum].busygrlist.head = pgrnode;
					break;
				}
			}
			flagGrnode = flagGrnode->next;
		}
	}
	sem_post(&osd->registerlock);
#endif
	return 0;
}

int IMP_OSD_ShowRgn(IMPRgnHandle handle, int grpNum, int showFlag)
{
	if (handle >= NR_MAX_OSD_REGION) {
		IMP_LOG_ERR(TAG, "%s, Invalidate IMPRgnHandle\n", __func__);
		return IMP_ERR_OSD_PARAM;
	}

	if (grpNum >= NR_MAX_OSD_GROUPS) {
		IMP_LOG_ERR(TAG, "%s, Invalidate Group Num\n", __func__);
		return IMP_ERR_OSD_CHNID;
	}

	IMPOsd *osd = getOsd();
	IMPOsdGrpRgnNode *pgrnode = &osd->group[grpNum].grnode[handle];
	IMPOsdRgnNode *prnode = &osd->rnode[handle];

	if (pgrnode->status == IMP_OSD_RGN_FREE) {
		IMP_LOG_ERR(TAG, "%s, the region %d hasn't been registed to group %d\n", __func__, handle, grpNum);
		return IMP_ERR_OSD_NOT_CONFIG;
	}

	sem_wait(&osd->semRgnList);
	pgrnode->grAttr.show = showFlag;
	if ((NULL != prnode->attrfifo)&&(0 == showFlag)) {
		fifo_clear(prnode->attrfifo);
	}
	sem_post(&osd->semRgnList);

	return 0;
}

int IMP_OSD_Start(int grpNum)
{
	if (grpNum >= NR_MAX_OSD_GROUPS) {
		IMP_LOG_ERR(TAG, "%s, Invalidate Group Num\n", __func__);
		return IMP_ERR_OSD_CHNID;
	}

	IMPOsd *osd = getOsd();
	osd->group[grpNum].is_work = 1;
	IMP_LOG_DBG(TAG, "[%s][%d]group:%d\n",__func__,__LINE__,grpNum);

	return 0;
}

int IMP_OSD_Stop(int grpNum)
{
	if (grpNum >= NR_MAX_OSD_GROUPS) {
		IMP_LOG_ERR(TAG, "%s, Invalidate Group Num\n", __func__);
		return IMP_ERR_OSD_CHNID;
	}

	IMPOsd *osd = getOsd();
	osd->group[grpNum].is_work = 0;
	IMP_LOG_DBG(TAG, "[%s][%d]group:%d\n",__func__,__LINE__,grpNum);

	return 0;
}

int IMP_OSD_SetPoolSize(int size)
{
	IMP_LOG_INFO(TAG, "IMP_OSD_SetPoolSize:%d\n", size);
	if (size <= 0)
		return IMP_ERR_OSD_PARAM;
	pool_size = size;
	return 0;
}

int IMP_OSD_Alloc(uint32_t *addr, uint8_t *saddr, uint32_t len)
{
        IMPAlloc alloc;

        memset(&alloc, 0, sizeof(IMPAlloc));
	IMP_Alloc(&alloc, len, "osd");
        memcpy(alloc.info.vaddr, saddr, len);
        *addr = alloc.info.paddr;

        return 0;
}

void* IMP_ISPOSD_Alloc(uint32_t size)
{
	IMPAlloc alloc_ipu;
	memset(&alloc_ipu, 0, sizeof(alloc_ipu));
	if (IMP_Alloc(&alloc_ipu, size, "IspOsdBuf") < 0) {
		IMP_LOG_ERR(TAG, "IMP_Alloc(%d) failed\n", size);
		return NULL;
	}
	return (void *)alloc_ipu.info.vaddr;
}

void IspOsdparamcheck_LineRect(IMPISPDrawBlockAttr *pstDrawAttr)
{
		IMP_LOG_ERR(TAG,"----------------------------------IspOsdparamcheck_LineRect start----------------------------------\n");
		IMP_LOG_ERR(TAG, "[%s]type(0:line 1:range 2:window)\n", __func__, pstDrawAttr->type);
		IMP_LOG_ERR(TAG, "[%s]line_alpha:%d,(r,g,b)=(%d,%d,%d),line_enable:%d,(startx,starty)=(%d,%d),(endx,endy)=(%d,%d),line_width:%d\n", __func__,
				(int)pstDrawAttr->cfg.line.enable,
				(int)pstDrawAttr->cfg.line.startx,
				(int)pstDrawAttr->cfg.line.starty,
				(int)pstDrawAttr->cfg.line.endx,
				(int)pstDrawAttr->cfg.line.endy,
				(int)pstDrawAttr->cfg.line.color.argb.r_value,
				(int)pstDrawAttr->cfg.line.color.argb.g_value,
				(int)pstDrawAttr->cfg.line.color.argb.b_value,
				(int)pstDrawAttr->cfg.line.width,
				(int)pstDrawAttr->cfg.line.alpha);
		IMP_LOG_ERR(TAG, "[%s]wind_enable:%d,wind_alpha:%d,(r,g,b)=(%d,%d,%d),(left,top)=(%d,%d),(width,height)=(%d,%d),line_width:%d\n", __func__,
				(int)pstDrawAttr->cfg.wind.enable,
				(int)pstDrawAttr->cfg.wind.left,
				(int)pstDrawAttr->cfg.wind.top,
				(int)pstDrawAttr->cfg.wind.width,
				(int)pstDrawAttr->cfg.wind.height,
				(int)pstDrawAttr->cfg.wind.color.argb.r_value,
				(int)pstDrawAttr->cfg.wind.color.argb.g_value,
				(int)pstDrawAttr->cfg.wind.color.argb.b_value,
				(int)pstDrawAttr->cfg.wind.line_width,
				(int)pstDrawAttr->cfg.wind.alpha);
	IMP_LOG_ERR(TAG,"----------------------------------IspOsdparamcheck_LineRect end----------------------------------\n");
	return ;
}

void IspOsdparamcheck_Pic(IMPISPOSDSingleAttr *pstOsdAttr)
{
	int j =0;
	IMP_LOG_ERR(TAG,"----------------------------------IspOsdparamcheck_Pic start----------------------------------\n");
	IMP_LOG_ERR(TAG, "[%s],index=%d,osd_type:%d(0:argb8888 1:argb1555),osd_pixel_alpha_disable:%d,osd_argb_type:%d\n", __func__,
			j,pstOsdAttr->chnOSDAttr.osd_type,pstOsdAttr->chnOSDAttr.osd_pixel_alpha_disable, pstOsdAttr->chnOSDAttr.osd_argb_type );
	IMP_LOG_ERR(TAG, "[%s]osd_enable=%d,(left,top)=(%d,%d),(w,h)=(%d,%d),stride:%d ,osd_image:%#x\n", __func__,
			pstOsdAttr->pic.osd_enable,
			pstOsdAttr->pic.osd_left,
			pstOsdAttr->pic.osd_top,
			pstOsdAttr->pic.osd_width,
			pstOsdAttr->pic.osd_height,
			pstOsdAttr->pic.osd_stride,
			pstOsdAttr->pic.osd_image);
	IMP_LOG_ERR(TAG,"----------------------------------IspOsdparamcheck_Pic end----------------------------------\n");
	return ;
}

int IspOsdParamAdjust_Pic(IMPISPOSDSingleAttr  *pstOsdAttr)
{
	if(!pstOsdAttr){
		IMP_LOG_ERR(TAG,"[%s][%d]pstOsdAttr is NULL\n",__func__,__LINE__);
		return -1;
	}
	int i = 0,j = 0,k = 0;
	uint16_t u16pic_srcw = 0,u16pic_srch = 0;
	uint16_t u16pic_srcstartx = 0,u16pic_srcstarty = 0,u16pic_srcendx = 0,u16pic_srcendy = 0;
	uint16_t u16pic_dststartx = 0,u16pic_dststarty = 0;
		/*如何确保俩俩相交不会乱码呢？
		  方案一：以数组序号为优先级，当出现相交时，手动调整pic位置，并抛出警告告知用户，这么做是因为ISP叠图片相交时出现乱码，需要调整位置
		  方法二：简单些，若数组区域有相交，直接不画（组内讨论暂不通过）*/

	if(1 == pstOsdAttr->pic.osd_enable) {
		u16pic_srcw = pstOsdAttr->pic.osd_width;
		u16pic_srch = pstOsdAttr->pic.osd_height;

		u16pic_srcstartx = pstOsdAttr->pic.osd_left;
		u16pic_srcstarty = pstOsdAttr->pic.osd_top;
		u16pic_srcendx = u16pic_srcstartx + u16pic_srcw;
		u16pic_srcendy = u16pic_srcstarty + u16pic_srch;

		if(1 == pstOsdAttr->pic.osd_enable) {
			u16pic_dststartx = pstOsdAttr->pic.osd_left;
			u16pic_dststarty = pstOsdAttr->pic.osd_top;

			/*比较、判断是否有相交重叠，若相交重叠则调整位置
			  (u16pic_srcstartx <= u16pic_dststartx <= u16pic_srcendx) && (u16pic_srcstarty <= u16pic_dststarty <= u16pic_srcendy)
			  */
			if( (u16pic_srcstartx < u16pic_dststartx  &&  u16pic_dststartx < u16pic_srcendx) &&
					(u16pic_srcstarty < u16pic_dststarty && u16pic_dststarty < u16pic_srcendy) ) {
				IMP_LOG_ERR(TAG,"[%s][%d]WARING,chn[%d]pic[%d] Overlap between pictures,now SDK adjust pic position(x:%d,y:%d)-->(newx:%d,newy:%d)\n",\
						__func__,__LINE__,i,k,u16pic_dststartx,u16pic_dststarty,u16pic_srcendx,u16pic_srcendy);
				pstOsdAttr->pic.osd_left = u16pic_srcendx;
				pstOsdAttr->pic.osd_top = u16pic_srcendy;
			}
		}
	}
	return 0;
}

void IspOsdparamcheck_Mask(IMPISPMaskBlockAttr *pmask)
{
		//矩形遮挡mask每个通道最多支持4个
	IMP_LOG_ERR(TAG,"----------------------------------IspOsdparamcheck_Mask start----------------------------------\n");
	IMP_LOG_ERR(TAG, "[%s]type(0:rgb 1:yuv)\n", __func__,pmask->mask_type);
	IMP_LOG_ERR(TAG, "[%s]mask_en:%d, (top,left)=(%d,%d), (width,height)=(%d,%d), type:%d, (r,g,b)=(%d,%d,%d)", __func__,
			pmask->mask_en,
			pmask->mask_pos_top,
			pmask->mask_pos_left,
			pmask->mask_width,
			pmask->mask_height,
			pmask->mask_type,
			pmask->mask_value.argb.r_value,
			pmask->mask_value.argb.g_value,
			pmask->mask_value.argb.b_value);
	IMP_LOG_ERR(TAG,"----------------------------------IspOsdparamcheck_Mask end----------------------------------\n");
	return ;
}

int IMP_OSD_SetRgnAttr_ISP(IMPOSDRgnAttr *prAttr,int bosdshow)
{
	int ret = 0;
	IMPISPDrawBlockAttr *pstDrawAttr = NULL;
	IMPISPOSDSingleAttr  *pstOsdAttr = NULL;
	IMPISPMaskBlockAttr *pmask = NULL;
	if(NULL == prAttr) {
		IMP_LOG_ERR(TAG, "%s, Invalidate prAttr\n", __func__);
		return IMP_ERR_OSD_NULL_PTR;
	}
	if(prAttr->type != OSD_REG_ISP_PIC && prAttr->type != OSD_REG_ISP_LINE_RECT && prAttr->type != OSD_REG_ISP_COVER) {
		IMP_LOG_ERR(TAG, "%s, prAttr->type:%d != (OSD_REG_ISP_PIC/OSD_REG_ISP_LINE_RECT/OSD_REG_ISP_COVER)\n", __func__,prAttr->type);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}

	IMPOsd *posd = getOsd();
	if(NULL == posd){
		IMP_LOG_ERR(TAG, "%s, getOsd() error,init osd resource first\n", __func__);
		return IMP_ERR_OSD_UNEXIST;
	}
	pthread_mutex_lock(&posd->ISPOsdmutex);
	posd->bISPopenosd = !!bosdshow;/*将bISPopenosd位设置为0或1*/
	pstDrawAttr = &prAttr->osdispdraw.stDrawAttr;
	pstOsdAttr = &prAttr->osdispdraw.stpicAttr;
	pmask = &prAttr->osdispdraw.stCoverAttr;
	/*该接口只支持三种ISP绘制OSD类型，一种叠加图片，一种叠加线、框，一种矩形遮挡*/
	if(prAttr->type == OSD_REG_ISP_LINE_RECT) {
		/*ISPOSD绘制线框类型*/
#ifdef ISPOSDDBG
		IspOsdparamcheck_LineRect(pstDrawAttr);
		printf("chn 0 [%d]-[%d]-[%d]-[%d]\n", pstDrawAttr->cfg.wind.left,
			pstDrawAttr->cfg.wind.top,
			pstDrawAttr->cfg.wind.width,
			pstDrawAttr->cfg.wind.height);
#endif
		ret = IMP_ISP_Tuning_SetDrawBlock(pstDrawAttr);
		if(ret < 0){
			pthread_mutex_unlock(&posd->ISPOsdmutex);
			IMP_LOG_ERR(TAG, "%s, IMP_ISP_Tuning_SetDrawBlock error,check param\n", __func__);
			return IMP_ERR_OSD_NOT_SUPPORT;
		}
	} else if(prAttr->type == OSD_REG_ISP_PIC) {
		/*ISPOSD绘制图片类型*/
		//!!!!!注意：现在ISP设置图片类型的都不使用这个接口，后续等ISP完成相关功能陆续使用创建handle号的形式
		IMP_LOG_ERR(TAG, "%s, Now, OSD_REG_ISP_PIC not use this interface! use IMP_OSD_CreateRgn_ISP \n", __func__);
		pthread_mutex_unlock(&posd->ISPOsdmutex);
		return IMP_ERR_OSD_NOT_SUPPORT;

#ifdef ISPOSDDBG
		IspOsdparamcheck_Pic(pstOsdAttr);
#endif
#if 0
		ret = IspOsdParamAdjust_Pic(pstOsdAttr);
		if(ret < 0) {
			pthread_mutex_unlock(&posd->ISPOsdmutex);
			IMP_LOG_ERR(TAG, "%s, IspOsdParamAdjust_Pic error,check param\n", __func__);
			return -1;
		}
		ret = IMP_ISP_SetOSDAttr(pstOsdAttr);
		if(ret < 0){
			pthread_mutex_unlock(&posd->ISPOsdmutex);
			IMP_LOG_ERR(TAG, "%s, IMP_ISP_SetOSDAttr error,check param\n", __func__);
			return -1;
		}
		/*ISP:ISP 要求在不改他们代码的前提下，设置一个pic后，需要将osd_image置NULL，这样他们内部就保存了上一次设置的结果，且不受其他块的影响*/
		/*单线程这里可以这样清空，但是当多线程调用OSD_REG_ISP_PIC模式，会清空，导致后运行线程的设置无法叠加OSD，后续该选项应放弃使用*/
		for(i = 0;i < 2;i++) {
			for (j = 0;j < MAXISPOSDPIC;j++) {
				pstOsdAttr->osd_chx[i].pic[j].osd_image = NULL;
			}
		}
#endif
	} else if (prAttr->type == OSD_REG_ISP_COVER) {
		/*ISPOSD 绘制矩形遮挡类型*/
#ifdef ISPOSDDBG
		IspOsdparamcheck_Mask(pmask);
#endif
		ret = IMP_ISP_Tuning_SetMaskBlock(pmask);
		if(ret < 0){
			pthread_mutex_unlock(&posd->ISPOsdmutex);
			IMP_LOG_ERR(TAG, "%s, IMP_ISP_Tuning_SetMaskBlock error,check param\n", __func__);
			return -1;
		}
	}
	pthread_mutex_unlock(&posd->ISPOsdmutex);
	return 0;
}

int IMP_OSD_GetRgnAttr_ISP(IMPOSDRgnAttr *prAttr,int *pbosdshow)
{
	int ret = 0;
	IMPISPOSDSingleAttr  *pstOsdAttr = NULL;
	IMPISPMaskBlockAttr *pmask = NULL;

	if(NULL == prAttr || NULL == pbosdshow) {
		IMP_LOG_ERR(TAG, "%s, Invalidate prAttr\n", __func__);
		return IMP_ERR_OSD_NULL_PTR;
	}
	IMPOsd *posd = getOsd();
	if(NULL == posd){
		IMP_LOG_ERR(TAG, "%s, getOsd() error,init osd resource first\n", __func__);
		return IMP_ERR_OSD_UNEXIST;
	}
	*pbosdshow = posd->bISPopenosd;

	/*该接口只能获取到ISP绘制OSD的相关属性信息*/
	pstOsdAttr = &prAttr->osdispdraw.stpicAttr;
	pmask = &prAttr->osdispdraw.stCoverAttr;

	ret= IMP_ISP_Tuning_GetOSDAttr(pstOsdAttr);
	if(ret < 0){
		IMP_LOG_ERR(TAG, "%s, IMP_ISP_GetOSDAttr error,check param\n", __func__);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}

	ret = IMP_ISP_Tuning_GetMaskBlock(pmask);
	if(ret < 0){
		IMP_LOG_ERR(TAG, "%s, IMP_ISP_Tuning_SetMask error,check param\n", __func__);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}
	return 0;
}

int IMP_OSD_SetRgnAttr_ISP_Sec(IMPOSDRgnAttr *prAttr,int bosdshow)
{
	int ret = 0;
	IMPISPDrawBlockAttr *pstDrawAttr = NULL;
	IMPISPOSDSingleAttr  *pstOsdAttr = NULL;
	IMPISPMaskBlockAttr *pmask = NULL;
	if(NULL == prAttr) {
		IMP_LOG_ERR(TAG, "%s, Invalidate prAttr\n", __func__);
		return IMP_ERR_OSD_NULL_PTR;
	}
	if(prAttr->type != OSD_REG_ISP_PIC && prAttr->type != OSD_REG_ISP_LINE_RECT && prAttr->type != OSD_REG_ISP_COVER) {
		IMP_LOG_ERR(TAG, "%s, prAttr->type:%d != (OSD_REG_ISP_PIC/OSD_REG_ISP_LINE_RECT/OSD_REG_ISP_COVER)\n", __func__,prAttr->type);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}

	IMPOsd *posd = getOsd();
	if(NULL == posd){
		IMP_LOG_ERR(TAG, "%s, getOsd() error,init osd resource first\n", __func__);
		return IMP_ERR_OSD_UNEXIST;
	}
	pthread_mutex_lock(&posd->ISPOsdmutex);
	posd->bISPopenosd = !!bosdshow;/*将bISPopenosd位设置为0或1*/
	pstDrawAttr = &prAttr->osdispdraw.stDrawAttr;
	pstOsdAttr = &prAttr->osdispdraw.stpicAttr;
	pmask = &prAttr->osdispdraw.stCoverAttr;
	/*该接口只支持三种ISP绘制OSD类型，一种叠加图片，一种叠加线、框，一种矩形遮挡*/
	if(prAttr->type == OSD_REG_ISP_LINE_RECT) {
		/*ISPOSD绘制线框类型*/
#ifdef ISPOSDDBG
		IspOsdparamcheck_LineRect(pstDrawAttr);
		printf("chn 1 [%d]-[%d]-[%d]-[%d]\n", pstDrawAttr->cfg.wind.left,
			pstDrawAttr->cfg.wind.top,
			pstDrawAttr->cfg.wind.width,
			pstDrawAttr->cfg.wind.height);
#endif
		ret = IMP_ISP_Tuning_SetDrawBlock_Sec(pstDrawAttr);
		if(ret < 0){
			pthread_mutex_unlock(&posd->ISPOsdmutex);
			IMP_LOG_ERR(TAG, "%s, IMP_ISP_Tuning_SetDrawBlock error,check param\n", __func__);
			return IMP_ERR_OSD_NOT_SUPPORT;
		}
	} else if(prAttr->type == OSD_REG_ISP_PIC) {
		/*ISPOSD绘制图片类型*/
		//!!!!!注意：现在ISP设置图片类型的都不使用这个接口，后续等ISP完成相关功能陆续使用创建handle号的形式
		IMP_LOG_ERR(TAG, "%s, Now, OSD_REG_ISP_PIC not use this interface! use IMP_OSD_CreateRgn_ISP \n", __func__);
		pthread_mutex_unlock(&posd->ISPOsdmutex);
		return IMP_ERR_OSD_NOT_SUPPORT;

#ifdef ISPOSDDBG
		IspOsdparamcheck_Pic(pstOsdAttr);
#endif
#if 0
		ret = IspOsdParamAdjust_Pic(pstOsdAttr);
		if(ret < 0) {
			pthread_mutex_unlock(&posd->ISPOsdmutex);
			IMP_LOG_ERR(TAG, "%s, IspOsdParamAdjust_Pic error,check param\n", __func__);
			return -1;
		}
		ret = IMP_ISP_SetOSDAttr(pstOsdAttr);
		if(ret < 0){
			pthread_mutex_unlock(&posd->ISPOsdmutex);
			IMP_LOG_ERR(TAG, "%s, IMP_ISP_SetOSDAttr error,check param\n", __func__);
			return -1;
		}
		/*ISP:ISP 要求在不改他们代码的前提下，设置一个pic后，需要将osd_image置NULL，这样他们内部就保存了上一次设置的结果，且不受其他块的影响*/
		/*单线程这里可以这样清空，但是当多线程调用OSD_REG_ISP_PIC模式，会清空，导致后运行线程的设置无法叠加OSD，后续该选项应放弃使用*/
		for(i = 0;i < 2;i++) {
			for (j = 0;j < MAXISPOSDPIC;j++) {
				pstOsdAttr->osd_chx[i].pic[j].osd_image = NULL;
			}
		}
#endif
	} else if (prAttr->type == OSD_REG_ISP_COVER) {
		/*ISPOSD 绘制矩形遮挡类型*/
#ifdef ISPOSDDBG
		IspOsdparamcheck_Mask(pmask);
#endif
		ret = IMP_ISP_Tuning_SetMaskBlock_Sec(pmask);
		if(ret < 0){
			pthread_mutex_unlock(&posd->ISPOsdmutex);
			IMP_LOG_ERR(TAG, "%s, IMP_ISP_Tuning_SetMaskBlock error,check param\n", __func__);
			return -1;
		}
	}
	pthread_mutex_unlock(&posd->ISPOsdmutex);
	return 0;
}

int IMP_OSD_GetRgnAttr_ISP_Sec(IMPOSDRgnAttr *prAttr,int *pbosdshow)
{
	int ret = 0;
	IMPISPOSDSingleAttr  *pstOsdAttr = NULL;
	IMPISPMaskBlockAttr *pmask = NULL;

	if(NULL == prAttr || NULL == pbosdshow) {
		IMP_LOG_ERR(TAG, "%s, Invalidate prAttr\n", __func__);
		return IMP_ERR_OSD_NULL_PTR;
	}
	IMPOsd *posd = getOsd();
	if(NULL == posd){
		IMP_LOG_ERR(TAG, "%s, getOsd() error,init osd resource first\n", __func__);
		return IMP_ERR_OSD_UNEXIST;
	}
	*pbosdshow = posd->bISPopenosd;

	/*该接口只能获取到ISP绘制OSD的相关属性信息*/
	pstOsdAttr = &prAttr->osdispdraw.stpicAttr;
	pmask = &prAttr->osdispdraw.stCoverAttr;

	ret= IMP_ISP_Tuning_GetOSDAttr_Sec(pstOsdAttr);
	if(ret < 0){
		IMP_LOG_ERR(TAG, "%s, IMP_ISP_GetOSDAttr error,check param\n", __func__);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}

	ret = IMP_ISP_Tuning_GetMaskBlock_Sec(pmask);
	if(ret < 0){
		IMP_LOG_ERR(TAG, "%s, IMP_ISP_Tuning_SetMask error,check param\n", __func__);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}
	return 0;
}


/*******************************************************************
 *
 *
 *
*******************************************************************/

int IMP_OSD_MultiCamera_SetRgnAttr_ISP(IMPVI_NUM num, IMPOSDRgnAttr *prAttr,int bosdshow)
{
	int ret = 0;
	IMPISPDrawBlockAttr *pstDrawAttr = NULL;
	IMPISPOSDSingleAttr  *pstOsdAttr = NULL;
	IMPISPMaskBlockAttr *pmask = NULL;
	if(NULL == prAttr) {
		IMP_LOG_ERR(TAG, "%s, Invalidate prAttr\n", __func__);
		return IMP_ERR_OSD_NULL_PTR;
	}
	if(prAttr->type != OSD_REG_ISP_PIC && prAttr->type != OSD_REG_ISP_LINE_RECT && prAttr->type != OSD_REG_ISP_COVER) {
		IMP_LOG_ERR(TAG, "%s, prAttr->type:%d != (OSD_REG_ISP_PIC/OSD_REG_ISP_LINE_RECT/OSD_REG_ISP_COVER)\n", __func__,prAttr->type);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}

	IMPOsd *posd = getOsd();
	if(NULL == posd){
		IMP_LOG_ERR(TAG, "%s, getOsd() error,init osd resource first\n", __func__);
		return IMP_ERR_OSD_UNEXIST;
	}
	pthread_mutex_lock(&posd->ISPOsdmutex);
	posd->bISPopenosd = !!bosdshow;/*将bISPopenosd位设置为0或1*/
	pstDrawAttr = &prAttr->osdispdraw.stDrawAttr;
	pstOsdAttr = &prAttr->osdispdraw.stpicAttr;
	pmask = &prAttr->osdispdraw.stCoverAttr;
	/*该接口只支持三种ISP绘制OSD类型，一种叠加图片，一种叠加线、框，一种矩形遮挡*/
	if(prAttr->type == OSD_REG_ISP_LINE_RECT) {
		/*ISPOSD绘制线框类型*/
#ifdef ISPOSDDBG
		IspOsdparamcheck_LineRect(pstDrawAttr);
		printf("chn 1 [%d]-[%d]-[%d]-[%d]\n", pstDrawAttr->cfg.wind.left,
			pstDrawAttr->cfg.wind.top,
			pstDrawAttr->cfg.wind.width,
			pstDrawAttr->cfg.wind.height);
#endif
		ret = IMP_ISP_MultiCamera_Tuning_SetDrawBlock(num, pstDrawAttr);
		if(ret < 0){
			pthread_mutex_unlock(&posd->ISPOsdmutex);
			IMP_LOG_ERR(TAG, "%s, IMP_ISP_Tuning_SetDrawBlock error,check param\n", __func__);
			return IMP_ERR_OSD_NOT_SUPPORT;
		}
	} else if(prAttr->type == OSD_REG_ISP_PIC) {
		/*ISPOSD绘制图片类型*/
		//!!!!!注意：现在ISP设置图片类型的都不使用这个接口，后续等ISP完成相关功能陆续使用创建handle号的形式
		IMP_LOG_ERR(TAG, "%s, Now, OSD_REG_ISP_PIC not use this interface! use IMP_OSD_CreateRgn_ISP \n", __func__);
		pthread_mutex_unlock(&posd->ISPOsdmutex);
		return IMP_ERR_OSD_NOT_SUPPORT;

#ifdef ISPOSDDBG
		IspOsdparamcheck_Pic(pstOsdAttr);
#endif
#if 0
		ret = IspOsdParamAdjust_Pic(pstOsdAttr);
		if(ret < 0) {
			pthread_mutex_unlock(&posd->ISPOsdmutex);
			IMP_LOG_ERR(TAG, "%s, IspOsdParamAdjust_Pic error,check param\n", __func__);
			return -1;
		}
		ret = IMP_ISP_SetOSDAttr(pstOsdAttr);
		if(ret < 0){
			pthread_mutex_unlock(&posd->ISPOsdmutex);
			IMP_LOG_ERR(TAG, "%s, IMP_ISP_SetOSDAttr error,check param\n", __func__);
			return -1;
		}
		/*ISP:ISP 要求在不改他们代码的前提下，设置一个pic后，需要将osd_image置NULL，这样他们内部就保存了上一次设置的结果，且不受其他块的影响*/
		/*单线程这里可以这样清空，但是当多线程调用OSD_REG_ISP_PIC模式，会清空，导致后运行线程的设置无法叠加OSD，后续该选项应放弃使用*/
		for(i = 0;i < 2;i++) {
			for (j = 0;j < MAXISPOSDPIC;j++) {
				pstOsdAttr->osd_chx[i].pic[j].osd_image = NULL;
			}
		}
#endif
	} else if (prAttr->type == OSD_REG_ISP_COVER) {
		/*ISPOSD 绘制矩形遮挡类型*/
#ifdef ISPOSDDBG
		IspOsdparamcheck_Mask(pmask);
#endif
		ret = IMP_ISP_MultiCamera_Tuning_SetMaskBlock(num, pmask);
		if(ret < 0){
			pthread_mutex_unlock(&posd->ISPOsdmutex);
			IMP_LOG_ERR(TAG, "%s, IMP_ISP_Tuning_SetMaskBlock error,check param\n", __func__);
			return -1;
		}
	}
	pthread_mutex_unlock(&posd->ISPOsdmutex);
	return 0;
}

int IMP_OSD_MultiCamera_GetRgnAttr_ISP(IMPVI_NUM num, IMPOSDRgnAttr *prAttr,int *pbosdshow)
{
	int ret = 0;
	IMPISPOSDSingleAttr  *pstOsdAttr = NULL;
	IMPISPMaskBlockAttr *pmask = NULL;

	if(NULL == prAttr || NULL == pbosdshow) {
		IMP_LOG_ERR(TAG, "%s, Invalidate prAttr\n", __func__);
		return IMP_ERR_OSD_NULL_PTR;
	}
	IMPOsd *posd = getOsd();
	if(NULL == posd){
		IMP_LOG_ERR(TAG, "%s, getOsd() error,init osd resource first\n", __func__);
		return IMP_ERR_OSD_UNEXIST;
	}
	*pbosdshow = posd->bISPopenosd;

	/*该接口只能获取到ISP绘制OSD的相关属性信息*/
	pstOsdAttr = &prAttr->osdispdraw.stpicAttr;
	pmask = &prAttr->osdispdraw.stCoverAttr;

	ret= IMP_ISP_MultiCamera_Tuning_GetOSDAttr(num, pstOsdAttr);
	if(ret < 0){
		IMP_LOG_ERR(TAG, "%s, IMP_ISP_GetOSDAttr error,check param\n", __func__);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}

	ret = IMP_ISP_MultiCamera_Tuning_GetMaskBlock(num, pmask);
	if(ret < 0){
		IMP_LOG_ERR(TAG, "%s, IMP_ISP_Tuning_SetMask error,check param\n", __func__);
		return IMP_ERR_OSD_NOT_SUPPORT;
	}
	return 0;
}
